Uh oh!
There was an error while loading. Please reload this page.
fix(devx): give check:llms-txt the population it re-derives, not the artifact it guards - #13302
Merged
Merged
Conversation
…artifact it guards check:llms-txt verifies packages/spec/llms.txt against trees elsewhere - the *.zod.ts counts under packages/spec/src, the api-surface/ shards, the manifest exports keys, and the non-private @objectstack/* workspace set - but reached every one of them through join(PKG, ...), so the only repo-relative literal it spelled was llms.txt itself. scripts/pm/dispatch-gates.mjs derives a card's gate family by scanning each gate's source for path literals, so it could name this gate only AFTER the artifact had been edited, while every edit that falsifies it lands somewhere else. Measured on PR #13186 across two rounds of one branch: deleting a src/ schema module moved src/kernel/ 32 -> 31 and the summed total 208 -> 207, the derived family did not contain the gate, and the red reached CI instead of the local sweep. The direction is the bad one - over-matching costs a wasted run, this under-matched silently and the tool's output gave no signal. Each input is now spelled repo-relative and joined onto ROOT, so the literals stay load-bearing: the file opens exactly the paths it declares. The repo-root workspace file and the per-package manifests, which cannot be spelled as literals this file opens, are declared in the established <file>/** form that check-doc-anchors and the pm line ratchet already use. Case 21 of the gate's own self-test binds the declaration to the reads, and earned that immediately: the first draft declared only packages/, and the case caught apps/* and examples/* being workspace roots this gate also opens. It derives the roots from the real pnpm-workspace.yaml rather than repeating a list, so the next new root fails at the gate that reads it. Thirteen pinned cases in the register's self-test hold both halves - the four trees are reached, and nothing else is. Priced over the 232 commits this checkout holds: the whole declared population matches 47 of them (20.3%), where a blanket packages/** would have bought the "22 leads is the same as none" failure the derivation's own header refuses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KX8wnyjStaZcuMyAMNsy3N
This was referenced Aug 29, 2026
Contributor
📓 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. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-project-manager
marked this pull request as ready for review
August 30, 2026 00:32
os-project-manager
enabled auto-merge
August 30, 2026 00:32
Uh oh!
There was an error while loading. Please reload this page.
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#13207
check:llms-txtre-derives the claims of the hand-keptpackages/spec/llms.txtagainst trees elsewhere — the*.zod.tscounts underpackages/spec/src, theapi-surface/shards, the manifestexportskeys, and the non-private@objectstack/*workspace set. But it reached every one of them throughjoin(PKG, ...), so the only repo-relative literal it spelled wasllms.txtitself.scripts/pm/dispatch-gates.mjsderives a card's gate family by scanning each gate's source for path literals. So the derivation could name this gate only after the artifact had already been edited, while every edit that actually falsifies it lands somewhere else. That is under-matching, the silent direction: an over-matching gate costs a wasted run, this one omitted itself and the tool's output gave no signal.Reproduce-first, on this branch, before the fix
Two rounds, same commit, family derived mechanically each time:
One route, and it is the artifact. That reproduces the card's measurement exactly.
After
Each input is spelled repo-relative and joined onto
ROOT, so the literals stay load-bearing — the file opens exactly the paths it declares, which is what keeps the declaration from drifting from what the gate really reads. The repo-root workspace file and the per-package manifests cannot be spelled as literals this file opens, so they are declared in the establishedFILE/**form thatcheck-doc-anchorsand the pm line ratchet already use.check:llms-txt?packages/spec/src/kernel/cluster.zod.tsgate source 'packages/spec/src'packages/spec/api-surface/data.jsongate source 'packages/spec/api-surface'packages/spec/package.jsongate source 'packages/spec/package.json'pnpm-workspace.yamlgate source 'pnpm-workspace.yaml/**'packages/drivers/driver-mongodb/package.jsongate source 'packages/**/package.json'packages/spec/llms.txtpackages/spec/docs/anything.mdpackages/rest/src/...content/docs/deployment/cli.mdxapps/docs/components/ui/card.tsxexamples/app-crm/src/objects/lead.object.tsThe acceptance criterion flips: a diff deleting a
src/schema module now names the gate, withllms.txtuntouched.Priced, not assumed
Over the 232 commits this checkout holds:
packages/**/package.jsonmatches 8 (3.4%), and the whole declared population matches 47 (20.3%). A blanketpackages/specorpackages/**would have bought the flip too — and the "22 leads is the same as none" failure the derivation's own header refuses. The negative rows above are the pins that hold that line.The anti-drift case earned its keep immediately
Case 21 of the gate's own self-test binds the declaration to the reads. The first draft declared only
packages/, and the case went red:pnpm-workspace.yamlalso listsapps/*andexamples/*, and this gate opens every manifest under them to build the package-ecosystem denominator. Neither root holds a non-private@objectstack/*package today and neither is touched by any of the 232 commits, so declaring them costs nothing measurable and closes the same hole one root over. The case now derives the roots from the realpnpm-workspace.yamlinstead of repeating a list, so the next new workspace root fails at the gate that reads it.Verification
Union re-run at final commit
6fd7443a:pnpm check:pm-dispatch-gates—dispatch-gates self-test: 892 cases pass(879 on base, +13 pinned here)pnpm --filter @objectstack/spec check:llms-txt—21 cases pass, then97 claim(s) re-derived ... (14 domains, 207 schemas) ... (68 published)pnpm --filter @objectstack/spec typecheck— exit 0; confirmed non-vacuous withtsc -p tsconfig.scripts.json --listFiles, which lists the edited file (1 hit)pnpm lint(repo-wideeslint . --no-inline-config) — exit 0, cleanpnpm check:nul-bytes— 7359 files, no raw control bytespnpm check:watch-hint-literal,check-self-test-wired, and the rest of the derived family: 39 of 43 pass; the other 4 are self-declared NOT MEASURED / PREREQUISITE NOT MET on an unbuilt tree or without a real GitHub token, not reds. This diff provably cannot move them: everytsupentry is undersrc/, andpackages/spec/scripts/is not in the packagefilesarray, so nothing here reaches anydist/.Ablation (no build or
dist/is involved — the self-test reads the gate source directly). Mutation applied to a committed tree, restore leg pinned toHEADwith an absolute path and anEXIT INT TERMtrap:const SRC_DIR = 'packages/spec/src';went to0occurrences and the blob hash moved916a9990->4948e1882 of 892 case(s) failed, precisely the two src casesgit diff HEADis emptyLanding
node scripts/pm/check-governed-merges.mjs --teston the final file list:0 of 2 path(s) hit the register— NOT governed, ordinary queue landing. No changeset: the diff publishes nothing (packages/spec/scripts/is not infiles,scripts/pm/ships from no package), soskip-changesetapplies.Scope
Disposition 1 only. Disposition 2 is #13300 in the skills lane and is not addressed here.
The card's follow-up question — does any other gate declare a population equal to its own guarded artifact — was run as a census over the register and is reported to the PM seat as a reading, not acted on: 33 of 183 discovered families have a non-self population of two files or fewer. Separately, #13301 was filed for
check:watch-hint-literalguarding onlyROOT_DIR_WATCH_HINTSwhile 41ROOT_FILE_WATCH_HINTSmentions carry the same silent-drop mechanism.Generated by Claude Code