* chore(#2387): refactor CONTEXT.md legacy content + add glossary drift gate
Apply the audit-and-enforce concept from the ADR index (#2356) to CONTEXT.md:
correct stale facts, and add a CI gate so the machine-verifiable claims can't
silently re-rot.
CONTEXT.md was entirely hand-maintained with nothing checking its claims against
the shipped tree, so it had rotted. An audit against live code (Memtrace +
filesystem + gh), each finding adversarially re-verified, drove 38 factual
corrections + 1 surfaced by the new gate:
- Dead references: Package Identity named @opengsd/get-shit-done-redux (package
is @opengsd/gsd-core); Shell Command Projection named run-git/run-npm/run-tool
(real exports execGit/execNpm/execTool); a partial docs/adr/1606 ref; retired
sdk/ framing.
- Superseded facts: allRuntimes 15 -> 17 (pi #2102, zcode); "seven nested-loader
runtimes" -> five (claude reverted flat #924, antigravity flat); stacked-PR
examples rebasing onto main -> next; QUOTA_SENTINELS precedence corrected to
match src/agent-command-router.cts.
- Drifted CONTRIBUTING.md line citations refreshed.
Per CONTRIBUTING.md:179, only stale FACTS were corrected -- no maintainer intent,
lesson, or opinion was rewritten, and the append-only session log is untouched
except one dated in-place superseding note. The three tests that assert on
CONTEXT.md content (phase6-capstone-conformance, tracer-bullet,
external-job-waiting) keep all their anchors.
New scripts/check-glossary-refs.cjs (--check, wired into lint:generated-sync):
- Check A: every backticked file reference under a TRACKED_PREFIXES allowlist
resolves on disk. Generated gsd-core/bin/lib/*.cjs (77 refs, gitignored),
~/-paths, .planning/, and bare filenames are deliberately skipped so a clean
CI checkout never false-fails.
- Check B: the allRuntimes count + member set in the glossary prose match
bin/install.js's allRuntimes literal (drifts on every runtime addition).
tests/check-glossary-refs.test.cjs covers both, including the false-positive
guard that a missing bin/lib/*.cjs ref does NOT trip the gate.
Closes#2387
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#2387): confine glossary-gate file refs to ROOT (no `..` traversal)
Pre-PR security review finding (low): extractTrackedRefs fed tokens straight to
fs.existsSync(path.join(ROOT, token)), and PATH_TOKEN_RE admits `.` in a segment,
so a CONTEXT.md token like `src/../../../etc/passwd` passed the `src/` prefix
check and normalized to an out-of-tree absolute path — turning the doc lint into
a filesystem-existence oracle on the CI host (existsSync only; CONTEXT.md is a
trusted committed file, hence low severity, but a defense-in-depth gap).
Add isWithinRoot() confinement in extractTrackedRefs: a token is dropped unless
path.resolve(ROOT, token) stays within ROOT. A CONTEXT.md reference is always a
plain in-repo path, so a `..` escape is never legitimate. Regression test asserts
a `..`-bearing token is skipped and never named in output.
Refs #2387
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#2387): drop legacy `get-shit-done` name from a CONTEXT.md defect entry
CI lint-legacy-dir-name failed: the line-928 upstream-issue re-point I applied
wrote the historical provenance as "gsd-build/get-shit-done#3545", and
scripts/lint-legacy-dir-name.cjs forbids the legacy `get-shit-done` name. Reword
to "moved from #3545 in the predecessor repo" — same provenance, no legacy name.
Caught by `npm run lint:ci` (the CI lint chain), which I had not run locally —
lint:generated-sync + eslint do not include lint-legacy-dir-name.
Refs #2387
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>