Files
msd-core/.changeset/3170-graphify-commit-staleness.md
Tom Boucher 29eb8be06d feat(graphify): commit-based staleness from built_at_commit (#3170) (#3171)
* test(graphify): TDD-red design contract for #3170 commit-staleness signal

Captures the proposed extension to graphifyStatus() as 8 failing
assertions across 3 groups (git-aware, non-git, back-compat). Suite is
describe.skip()'d so npm test stays green on the branch — removing
.skip is the green-light moment when the enhancement is approved and
implementation lands.

Verified against safishamsi/graphify v0.7.0 release notes: the field
on graph.json is built_at_commit (full git HEAD), not commit_hash as
originally guessed in #3170. Tests assert against the verified name.

Design highlights captured in the file's docstring:
- Tri-state commit_stale (true/false/null) — null means "we don't
  know" (pre-v0.7 graph or no git), distinct from false ("known fresh")
- Argument-injection fence /^[0-9a-f]{4,40}$/i validates built_at_commit
  before it reaches `git` as an argv element
- Existing graphifyStatus() fields (node_count, edge_count, stale,
  age_hours, etc.) are unchanged — back-compat fenced

Per the issue's enhancement template: no PR will be opened until the
issue is labeled `approved-enhancement`.

Refs #3170
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(graphify): surface commit-based staleness from graphify v0.7+ built_at_commit

Closes #3170

graphify v0.7+ embeds built_at_commit (full git HEAD) into graph.json at
write time. GSD's existing graphifyStatus() ignored it; staleness was
mtime-only, which is a poor proxy for "does this graph reflect the
current code." A CI-built graph rebuilt minutes ago against an old
checkout reads as FRESH on mtime but is materially stale.

graphifyStatus() now returns four additional fields on the success path:

  built_at_commit   short hash from graph.built_at_commit, or null
  current_commit    short hash of git HEAD, or null when no git
  commits_behind    git rev-list --count <built>..HEAD, or null
  commit_stale      true | false | null

Tri-state on commit_stale is load-bearing. null means "we don't know"
(pre-v0.7 graph, non-git cwd, unreachable commit) — semantically
distinct from false ("known fresh"). Agents reading null should fall
back to mtime; reading false can confidently skip a rebuild.

Security: built_at_commit is on-disk and user-influenceable. Without
validation, a hostile value (e.g. "--upload-pack=evil") would reach git
as an argv element and be interpreted as an option. The
/^[0-9a-f]{4,40}$/i fence rejects anything else as absent. spawnSync's
array args (no shell) is defense in depth, not the boundary.

Skill (commands/gsd/graphify.md) Step 2b renders one conditional line:

  Source commit: abc1234 (5 commits behind HEAD)
  Source commit: abc1234 (current)
  Source commit: abc1234 (freshness unknown)

Pre-v0.7 graphs omit the line entirely — no confusing "Source commit:
unknown" rendered.

Also documents `graphify hook install` in docs/CONFIGURATION.md for
multi-dev teams who would otherwise hit graph.json merge conflicts on
parallel rebuilds (sub-enhancement 2 from #3170).

TDD red→green: tests/enh-3170-graphify-commit-staleness.test.cjs
(8 assertions across git-aware, non-git, back-compat) was committed
describe.skip()'d in c567f23d when the issue was filed; this commit
removes .skip and lands the implementation that makes them green.
Full suite 7503/7503 passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 11:59:53 -04:00

5 lines
1.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
type: Enhancement
---
**`/gsd-graphify status` surfaces graphify v0.7+ commit-based staleness (#3170)** — `graphifyStatus()` now reads `built_at_commit` from `graph.json` (written by graphify v0.7+ at build time), compares it against `git HEAD`, and returns four new fields: `built_at_commit`, `current_commit`, `commits_behind`, and `commit_stale`. The `commit_stale` flag is tri-state — `true` / `false` / `null`, where `null` means the signal is unavailable (pre-v0.7 graph, non-git checkout, or unreachable commit) and callers should fall back to the existing mtime-based `stale` flag. The skill renders `Source commit: <hash> (N commits behind HEAD | current | freshness unknown)` when the signal is present, and omits the line entirely for pre-v0.7 graphs. The `built_at_commit` value is validated as 4–40 hex chars before reaching `git`, so a hostile `graph.json` cannot smuggle dashed options (e.g. `--upload-pack=…`) into the argv. Also documents `graphify hook install` in `docs/CONFIGURATION.md` for multi-dev teams who would otherwise hit `graph.json` merge conflicts on parallel rebuilds.