* fix(#2778): exempt intentionally-absent paths from the glossary gate
check-glossary-refs asserts that every backticked tests/ token in
CONTEXT.md resolves on disk. tests/emitted-drift-ack.json (ADR-2719
section 3) is absent on a healthy next BY DESIGN — it appears only
inside a PR that needs it, which is what makes touching it the alarm.
It passed before only by accident of backtick pairing: CONTEXT.md's
RULESET entries are themselves backtick-wrapped and contain backticks,
so the token happened to fall outside a code span. Any edit that
shifted the parity exposed it. A gate that passes by luck is not
passing.
The exemption is exact, not a prefix hole: a sibling missing tests/
path still fails, and a test locks that.
* feat(#2778): make the size-ratchet failure name its own remedy
The growth branch stated a requirement and withheld the means of
satisfying it: no ack file named, no schema, no key format, and no
do-not-regenerate line — so the likeliest guess was to hunt for a
baseline that #2724 deleted. Observed live on #2543.
All remediation now comes from one frozen REMEDIATION export whose
example document is rendered from ACK_VERSION, so the taught schema
cannot drift from the schema parseAck accepts. A round-trip test feeds
the printed document back through parseAck.
The report is now built as a typed IR (buildReport) that formatReport
renders, so tests assert on structure rather than prose, per
CONTRIBUTING.md's raw-text-matching rule.
Two defects found and fixed inline while building:
- diffEmitted's validation early-return omitted newFileCapExceeded
while formatReport reads its length, so the branch that reports a
failed git diff threw a TypeError instead of naming the problem.
- Printing one complete ack document per failing branch made each read
as the whole file, so pasting the second over the first silently lost
an acknowledgment. One document now covers the whole report.
Closes#2778
* chore(#2778): backfill changeset pr number to 2780
* 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>