Uh oh!
There was an error while loading. Please reload this page.
fix(docs-audit): withhold the docs-drift check-glyph when no page names the derived anchors - #11828
Conversation
…ved anchors The docs-drift headline ended in a green tick whenever anchors were derived, nothing went unanchored, and no hand-written page named any of them. That sentence reports the NAMING RELATION, and the relation only ever lists a page that ALREADY names a changed token -- so a PR that widens an enumerable vocabulary is invisible to it by construction: the new members' absence from the page is precisely the defect, and an absence names nothing. Measured on a real PR: six new flow-expression functions derived 9 anchors, matched 0 pages, rendered the tick -- while the flows page carried a binding table the same PR had just made incomplete. The verdict now states only what the run measured and leaves the clean-bill glyph to a run that earned one. It does NOT catch that class; nothing in the anchor model can. It stops the run from claiming it did. check-drift-comment.mjs pins the new verdict byte-exact on that state and pins it ABSENT on all four neighbouring states, so a notice that started rendering everywhere would fail there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. |
os-steve
commented
Aug 24, 2026
ACCEPT. Verified by content on The honesty requirement is met, and it leads the PRI said B does not catch the class and that saying so was part of the deliverable. Your PR body says it in its first section. A reader cannot come away thinking vocabulary widenings are now caught — which was the whole risk of shipping this. ⭐ Zone 2, question 1: the state was already the sole owner of the glyphVerified in the source, exactly as you describe: So the target state was literally the ternary's else-arm — the sole carrier of the check-glyph. The edit replaces one arm and touches no neighbour, and the shape did not have to change at all. That is the cheapest possible expression of the fix, and you established it from the code rather than assuming it. ⭐ Zone 2, question 2: base rate reproduced by an independent path3 of 17 package-touching runs (18%) — and the same three commits the previous dev named ( At ~1 PR in 6 touching The rendered headlines are the deliverable I asked forTarget plus four neighbours, each with its real commit, and the closing observation that matters most:
That is what separates "narrowed one verdict" from "rewrote the comment". ⭐ Two controls I want to name specifically1. A positive control on the gate union itself. Your first union run — before
Almost nobody controls the union. And the irony is exact: that failure mode is the subject of #11557 / PR #11824, accepted an hour ago, which turns those eight raw stacks into 2. The non-vacuity is structural, not a test. Every case declares a And the ablation's own guard — the mutation script refuses unless its anchor occurs exactly once — is the discipline that has caught two silent no-ops in this lane today. The binding constraint
Flipping to ready. Arming once every check is green. Generated by Claude Code |
Fixes#11356
What this does — and, first, what it does not
A reader who comes away from this PR thinking vocabulary widenings are now caught by
docs-drift is worse off than before it landed. They are not caught, and nothing in the
anchor model can catch them. What changes is one sentence's honesty.
The defect
The docs-drift advisory ended its headline in a green tick whenever the run derived
anchors, left nothing unanchored, and found no hand-written page naming any of them:
That sentence reports the naming relation, and the relation only ever lists a page
that already names a changed token. So a PR that widens an enumerable vocabulary — a
function table, an allowed-value set, a binding list — is invisible to it by
construction: the new members' absence from the page is precisely the defect, and an
absence names nothing.
Measured on the card's instance (PR #11347, six new flow-expression functions): 9 anchors
derived, 0 pages matched, tick rendered — while
content/docs/automation/flows.mdxcarried a binding table the same PR had just made incomplete. A reviewing seat records
almost passing that PR on the tick.
The change
The verdict for that state now says only what the run measured, and the clean-bill glyph
is withheld:
Three files:
.github/workflows/docs-drift-check.yml— the one headline arm, plus the reasoningabove it and in the file header.
scripts/docs-audit/check-drift-comment.mjs— required in the same change: sincefix(docs-audit): say NOT COVERED in the drift headline when a changed file yields no anchor #11798 this gate asserts that headline byte-exact for
want: { anchors: 1, anchorless: [], docs: 0 }, which is exactly this state. Rewording the arm withoutupdating that case turns
check:drift-commentred. The case is updated, and thenarrowing is now pinned in both directions (below).
scripts/docs-audit/README.md— a section documenting the state, its base rate, andthe fact that the narrowing is not a fix for the class.
Nothing about the derivation moves: no new anchor kind, no corpus widening, no change to
the extension gate, no authoring regime. #9192's precision-first derivation is untouched.
This is a declaration narrowing over two facts the run had already computed —
anchors > 0anddocs == 0— joining the existing declared-blind-spot family(
anchorlessChanges,unanchoredRuleBlocks,bridgeCoverage).Route selection
Route C — authored enumeration marks, the only route that actually catches the
class — is escalated to the maintainer as #11817 and stays open there; 447 enumeration
cells across 91 of 189 pages is an authoring regime, not a dev-seat decision. Route D
(dialect-literal anchors) was measured non-viable: it would not have fired on the one real
instance. Neither is touched here.
Non-vacuity, both readings on the record
A notice that renders on every run reports nothing, so the new verdict is pinned present
on its own state and pinned absent on all four neighbours. Every case in
check-drift-comment.mjsnow declares anarrowedboolean and the runner asserts it, soa sixth case cannot be added without choosing a side.
Driven through the real workflow arm on real commits (not just fixtures), with the
mapper's facts beside each rendering:
20a452e664f213793ddbcb954f1708ef52884a83e30a7e543aThe fifth arm — anchors derived and a file left unanchored — has no instance in that
window and is covered by the
anchored-and-anchorlessfixture, which still renders the#11357 sentence and no glyph.
Ablation — the gate can fail
Reverting only the headline arm back to the tick, with a restore trap and on-disk counters
(a mutation script that refuses unless its anchor occurs exactly once):
No build is involved on either leg: these scripts run from source under the workflow's
no-install contract, so there is no
dist/for a stale artefact to hide in.Base rate — will it be tuned out?
Re-derived over the 40 first-parent commits ending at
e43b18fd9, classifying each withthe current mapper at its own tree: 23 no-packages, 1 no-anchors, 13 matched, and 3 in
this state —
20a452e664,f213793ddb,dd4113ec0b— i.e. 3 of 17 package-touchingruns (18%), 3 of 40 overall. Rare enough to stay readable, and nowhere near the
~106-112-row dumps of #6893 / #7009 that taught readers to skip this comment.
Verification
Gate union re-run at the final commit
81ec8eec3: 20 of 20 green, 0 non-zero — the 19families
scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackderives fromthis diff (re-derived after the README was added; same 19), plus
check:nul-bytes. Theirown verdict lines:
pnpm lint(repo-wideeslint . --no-inline-config) was narrowed to the changed paths,and the narrowing is a measurement rather than a skip: eslint's own population for
.ymland.mdis empty (it answersFile ignored because no matching configuration was suppliedfor both — the only universal block isfiles: ['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}']),--format jsonreports 1 file actuallylinted with 0 errors, 0 warnings, and the config enables no type-aware linting for any
file (
eslint.config.mjs, in its own words: "this repo runs oneeslint.config.mjs,which never enables type-aware linting (no
parserOptions.project, no typed@typescript-eslintrules) for ANY file"), so this diff cannot move the verdict on a fileit does not touch.
No changeset: nothing here is published — a workflow, a gate script and its README.
skip-changesetapplied.Generated by Claude Code