Uh oh!
There was an error while loading. Please reload this page.
fix(check-doc-anchors): spell the heading-ids remedy so it cannot be read as a watch-hint declaration - #13775
Merged
os-project-manager merged 1 commit intoAug 31, 2026
Conversation
…read as a watch-hint declaration The remedy line printed for a broken anchor is a command for a human to paste at the repo root, and it carried the module specifier as a quoted relative literal `'./scripts/check-doc-anchors.mjs'`. The dispatch watch-hint extractor reads quoted path-shaped literals in a gate's module body and resolves the relative ones against the writer's own directory, so this gate — which lives in scripts/ — declared a path that has never existed on this tree, and that lead was pasted into every dispatch prompt the family matched. Neither half was wrong on its own; the fabrication came from prose being read as a declaration. Tightening the reader was measured and refused upstream, so the producer spells the path absolutely instead: process.cwd() + a leading-slash literal, which the extractor's admission test refuses outright while the command stays runnable verbatim from the repo root. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
os-project-manager
marked this pull request as ready for review
August 31, 2026 11:32
Uh oh!
There was an error while loading. Please reload this page.
os-project-manager
deleted the
claude/issue-13449-doc-anchors-remedy-literal
branch
August 31, 2026 11:54
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#13449
check:doc-anchorsprinted a remedy command whose module specifier was a quotedrelative literal. The dispatch watch-hint extractor reads quoted path-shaped literals
out of a gate's module body and resolves the relative ones against the directory of the
file that wrote them — so this gate, which lives in
scripts/, declared a path with itsown prefix doubled. That lead named a file that has never existed on this tree, and it
was pasted into every dispatch prompt whose file surface brushed the family.
Neither half was wrong on its own: the remedy is correct for its reader, the extractor is
correct about a declaration. The fabrication came from one being read as the other, so the
repair is local to the producer — spell the path so it cannot be read as a declaration.
Per the triage ruling, the extractor is not touched (upstream measured the tightening
at 8.6 real populations deleted per fabrication removed), and nothing in this delivery
touches
scripts/pm/dispatch-gates.mjs.The change
One line in
scripts/check-doc-anchors.mjs, plus the rationale comment above it:The leading
/inside the quotes is the whole mechanism.extractWatchHints' admissiontest is
/^[\w.@][\w.@/*-]*$/— a literal must begin with a word character,.or@—so an absolute path is refused outright, before the module-relative resolve can ever run.
process.cwd()is what keeps the command runnable verbatim from the repo root.A2.1 — the defect was still live at my ref
Re-confirmed at
c42bc8ee6(my branch point), not inherited from the dispatch order:The zero is a true zero, so #13312's closing PR did not absorb this. The card correctly
gets a PR rather than a close.
A2.2 — census: 1 site, and it is the only one
Two independent sweeps, both run through the real extractor rather than by eye.
Fleet sweep — every tracked gate/tooling script under a
scripts/directory(333 files), classifying each extracted hint that reaches nothing in the tree, and
flagging the doubled-prefix signature (a dead hint that becomes a real path when one copy
of the writer's own directory is stripped):
Same-file sweep — every quoted module-relative literal in
check-doc-anchors.mjs:4 of them, and the other 3 are genuine sibling import specifiers
(
./import-prerequisite.mjs,./check-adr-links.mjs,./invoked-as.mjs), which theextractor already refuses as single-segment siblings. Line 459 was the only remedy string.
⇒ 1 hit, fixed; 0 identical second sites left behind. After the change the same fleet
sweep reads
hints total: 1499 · dead: 735 · DOUBLED-PREFIX class: 0— exactly onehint removed and nothing else moved.
The remaining 735 dead hints are the fixture-constant class #13312 owns, a different
cause; they are untouched here.
A2.3 — reverse verification: the extractor emitted it before and does not after
Run against the committed implementation, mutating the tree back to the pre-fix spelling
and restoring it, with the mutation proved on disk by anchored
grep -con both theinjected and the removed text, and the restore proved by observed state (empty
git diff HEADplus a blob-hash comparison against the HEAD blob) rather than by an exitcode. The extractor is a pure string function over the source file as read from disk, so
there is no build artifact between the mutation and the reading.
Direction observed: the fabricated hint disappears and the three real declarations stay
—
content/**,README.md/**,ARCHITECTURE.md/**are byte-identical before and after,and nothing new is added. That last half matters: a spelling that merely moved the literal
(say, a bare
scripts/check-doc-anchors.mjs) would have been admitted as a true hintand quietly given this gate a population it does not read. This one declares nothing.
The same result is confirmed by the tool's own suite:
dispatch-gates.mjs --self-testreads this file live and asserts that the doc-anchors family still reaches
content/docs/deployment/cli.mdx, still claimsREADME.mdandARCHITECTURE.md, andstill claims neither instruction file. 1017 cases pass.
One more observed side-effect, in the right direction: the rationale comment added above
the line spells the relative path in prose, and the module-body sweep confirms comment
masking removes it — the file's RAW text has 4 module-relative literals, its masked module
body has 3.
A2.4 — the remedy still runs verbatim from the repo root
The gate was driven to its failure branch against a throwaway fixture root so the remedy
is the text a human actually sees:
(
FILEabove stands for the literal placeholder the gate prints, which the reader replaces.)Pasted verbatim at the repo root with the placeholder filled in:
Byte-identical to the same run under the old spelling —
diffof the two captures isempty. Readability does not regress: the command is one token longer and still a single
paste.
Gates
Family derived after the final commit with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no paths passed —the script takes its own change set; it reported
1 path(s) vs merge base c42bc8ee6).Every exit code below was captured before any pipe, and each verdict is the gate's own
printed line. All runs are on the final commit
fd2ea143f.Path-derived family (13):
pnpm check:agent-test-spellingpnpm check:bash32-floorpnpm check:cli-command-idspnpm check:cross-package-test-inputspnpm check:doc-anchorscheck-doc-anchors: 287 internal #fragment link(s) across 409 source file(s) all resolve to a real headingpnpm check:entry-guardpnpm check:parse-guardpnpm check:pnpm-filter-targetspnpm check:watch-hint-literal34 declaration(s) across 4 rostered name(s) … no unrostered spelling of the idiom in the treenode scripts/check-ci-filter-parity.mjsnode scripts/check-cross-package-test-inputs.mjsnode scripts/check-shard-attestation.mjsnode scripts/check-test-completeness.mjsPREREQUISITE NOT MET; it grades a savedturbo run testlog and none was named. Its own text says exit 3 is not a finding.Convention-triggered (editing a gate script), both named by the derivation:
node scripts/pm/bare-root-worklist.mjs --self-test51 live row(s), 43 unreachable as spelled, 43 recorded verdict(s) — none stale, none missing, none contradictedpnpm check:pm-dispatch-gatesdispatch-gates self-test: 1017 cases pass.Beyond the derived list, the gate script's own suite plus the consumers that read this
file by name (the "which tests test this script" half the path derivation cannot answer):
pnpm check:nul-bytesscanned 7578 text file(s) … no raw ASCII control bytespnpm check:published-readme-linksheadingIdsfrom the edited file)pnpm check:docs-single-h1pnpm check:docs-image-tagnode scripts/check-self-test-wired.mjs(+--self-test)node scripts/check-self-test-workflow-commands.mjs(+--self-test)pnpm lint(repo-wideeslint . --no-inline-config, not narrowed)Repo-wide ESLint was run in full rather than narrowed, so no narrowing is being declared.
Changeset
skip-changeset, applied at PR creation.Check Changesetis path-blind — it counts thechangesets a PR adds against the merge base and fails on zero; its only exemptions are
the
skip-changesetlabel and the Changesets release branch. This PR publishes nothing:the root manifest is
private, and no published package'sfilesfield escapes its owndirectory, so a repo-root
scripts/file ships in no tarball.Out of scope, deliberately
scripts/pm/dispatch-gates.mjsis untouched — [finding]hintCoversdoes not follow a final-segment basename glob, so.changeset/*.mdmeasures DEAD against ~400 tracked changesets — and the residue names a false reason for it #13448's landing site, in flight in thesame wave.
dispatch-gates --residueprints THREE fabricated leads for check:query-options-erasure — literals naming files that have never existed, unannotated because one live sibling keeps the family reachable #13312's cause) are untouched.Generated by Claude Code