Declare the packages/examples census subtree check-system-context-census actually reads - #14323

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration
Sep 2, 2026
Merged

Declare the packages/examples census subtree check-system-context-census actually reads#14323
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration

Conversation

@baozhoutao

@baozhoutaobaozhoutao commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14131

check-system-context-census.mjs spelled 29 path literals — the page it maintains, the
four colliding isSystem declarations, the NON_READ_ANCHORS citations — and not one of
them is its population. isystem-census.mjs builds the census from
git ls-files packages examples, so a diff that merely SHIFTS a cited line reds the gate
in Lint & Repo Gates while the dispatch derivation places it in the silent bucket,
which reads as a clearance and is not.

Measured cost, from this card and its comments: three CI laps plus three repair dispatches
in one night, on three unrelated PRs, each after a dev had honestly run its derived
families and honestly reported green.

Premise re-check on fresh origin/main (a39b02a6b, clean tree) — HOLDS

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack \
--residue packages/metadata-protocol/src/protocol.ts
-> Silent (source names paths, none of which cover yours): 139 famil(ies)
- node scripts/check-system-context-census.mjs [lint.yml] names:
content/docs/permissions/system-context.mdx, packages/spec/src/kernel/execution-context.zod.ts, ...
(3 of 29 declared literals reach nothing tracked)
node scripts/check-system-context-census.mjs # exit captured before any pipe
-> EXIT 0: 109 elevation read sites in 20 packages across 45 files, all anchored;
145 anchors resolve, 27 declared non-read

Every number in the card re-derived unchanged (109 / 20 / 45 / 145). The Silent bucket is
139 today, not the 127 the card recorded — re-derived, not quoted.

Deliverable 1 — the Silent-bucket census, MEASURED

The engine seat's first-deliverable fence: classify the Silent families by "declared
population vs actually-read population". Static classification was tried first and was not
good enough (a recursive walk(dir) hides its seed root), so the population was
measured instead: every one of the 139 Silent families was run under an fs-tracing
preload that records the repo-relative path of every readFileSync / readdirSync /
git ls-files the gate makes, and the trace was compared against the literals
extractWatchHints reads out of that family's own sources.

Definition used, stated so the number is checkable: content reads only
(readFileSync/readFile/openSync/createReadStream) — statSync/existsSync probes
are excluded — of tracked files, minus the 5-path footprint pnpm itself reads.

bucketfamilies
read 20+ tracked files under packages/ or examples/ that no declared literal covers49
read 20+ undeclared tracked files anywhere53
read 1..19 undeclared files83
declaration covers every file read, or nothing tracked was read3
(of the 139, exited non-zero — trace is partial, so these UNDER-count)22

So this card is one member of a class, not a one-gate defect. The top of the list,
undeclared reads after declared literals:

familydeclaredundeclared reads
pnpm check:nul-bytes27815
node scripts/check-closing-keyword-parity.mjs67811
node scripts/check-self-test-workflow-commands.mjs76360
node scripts/check-position-name-fold-loaders.mjs76251
pnpm check:refd-timer-probe55661
node scripts/check-comment-mask-corpus.mjs15661
pnpm check:vendor-version-stamps25660
pnpm check:skill-identifier-liveness175495
pnpm check:parse-guard25449
pnpm check:engine-double-contract15410
node scripts/check-system-context-census.mjs295387
pnpm check:error-code-casing235161
node scripts/check-tenant-audit-census.mjs244177

⚠️ What the number is NOT: reads are an upper bound on the verdict-bearing population.
A gate that opens every package.json to build a workspace list reads far more than can
red it. Four were verified by reading the source — check:engine-double-contract
(SCAN_ROOTS = ['packages', 'examples'], one declared literal),
check:error-code-casing (SCAN_ROOTS = ['packages']), check:route-envelope
(walk(join(ROOT, 'packages'))), check:error-status-conformance (walk(SCAN_ROOT)) —
and all four are the same shape as this card. ⛔ The remaining members are NOT asserted to
each want this repair; three of the largest provably cannot take it (see below).

Already-worked subsets, so nothing here is re-filed:#13519 / PR #14188 repaired four
gates by declaring what they read; #14189 carries the three whole-tree gates
(check:nul-bytes, check-comment-mask-corpus, check:refd-timer-probe) for which a
truthful declaration is "every file" and is therefore refused by the derivation's own
"22 leads is the same as none" rule. The residue between those seven and the 49 measured
here is filed as a new finding (linked from this PR's card comment) — ⛔ not fixed here,
and its derivation-layer half queues behind #14013, which holds
scripts/pm/dispatch-gates.mjs right now.

Deliverable 2 — the family-bloat cost of the wide declaration, MEASURED FIRST

The services seat's fence: ⛔ do not adopt the wide declaration before measuring what it
costs an ordinary diff. Families derived per probe path, before -> after, at a39b02a6b:

probe pathbeforeafter
packages/lint/src/authoring-rules.ts1920
packages/plugins/plugin-auth/src/auth-plugin.ts2223
packages/metadata-protocol/src/protocol.ts2122
packages/spec/src/data/object.zod.ts4242 (already named — it is a declared literal)
examples/app-crm/package.json1718
content/docs/permissions/access-matrix.mdx3030
scripts/check-nul-bytes.mjs1414
.github/workflows/lint.yml2323

+1 family, and only on cards under the two declared subtrees. Nothing outside them
moves. The gate it adds runs in ~3s and CI runs it on every PR regardless, so the local
cost is one command against the CI lap it replaces. That is the measurement the services
seat asked for, and it is what carries the decision below.

The declaration shipped: WIDE

ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**'], the idiom
check-tenant-audit-census.mjs:146 already carries and check-watch-hint-literal already
gates. ⛔ No second pattern invented.

Narrow (the 20 packages / 45 files that carry a read site today) was considered and
refused on the gate's own terms: a roster of the files that carry a read site TODAY can
never name the file that grows one TOMORROW, and a NEW read site is exactly what check B
— the mandatory POPULATION half — exists to catch. A narrow declaration derives green for
the one case that most needs the lead, so it re-introduces this defect wearing the shape
of a fix. The services seat leaned the same way; the measurement above is what made it a
decision rather than a preference.

What holds the declaration honest

isystem-census.mjs now names its corpus roots once (CORPUS_ROOTS), collectCorpus
walks that constant, and the gate's --self-test derives both directions from it:
every walked root is declared, and no declared root is unwalked. A corpus root added or
dropped reds here instead of silently outrunning the declaration.

Reverse verification (both mutations on the committed tree, both legs restored)

Predicted direction: RED, plus the derivation dropping the gate.

MUTATION A the computed spelling ROOT_DIR_WATCH_HINTS = CORPUS_ROOTS.map(...)
on-disk proof: literal line 1 -> 0, computed line present, blob da3189a39 != HEAD 804912155
self-test EXIT 1 "declared exactly once, as an array of quoted literals"
check-watch-hint-literal EXIT 1 "the declaration is COMPUTED, not a literal array"
derivation for packages/lint/src/authoring-rules.ts 20 -> 19, census named: NO
MUTATION B drop one walked root ROOT_DIR_WATCH_HINTS = ['packages/**']
on-disk proof: new line present, old line absent, blob c44b2c2b4 != HEAD
self-test EXIT 1 "every root the census walks is declared"
restore (git checkout HEAD -- path, absolute, trap-guarded): git diff HEAD EMPTY and
hash-object == HEAD blob 804912155 after BOTH legs; post-restore self-test EXIT 0

Mutation A is the load-bearing one: identical runtime value, every runtime assertion still
green, and zero hints extracted — the measured proof that the literal spelling is what
carries this fix.

Checks run — union at 03edd9ce5 (the final commit of this branch)

Derived for the real changeset with node scripts/pm/dispatch-gates.mjs (no paths — the
script takes the change set off the merge base itself): 16 families, 14 by path + 2 by
change kind.

check:agent-test-spelling EXIT 0
check:bash32-floor EXIT 0
check:cli-command-ids EXIT 0
check:cross-package-test-inputs EXIT 0
check:entry-guard EXIT 0
check:parse-guard EXIT 0
check:pnpm-filter-targets EXIT 0
check:ratchet-remedy-authority EXIT 0 (named in the dispatch)
check:watch-hint-literal EXIT 0 43 declarations, ROOT_DIR_WATCH_HINTS 29
check:declared-population-live EXIT 0 156 of 200 families declare a live population
check:nul-bytes EXIT 0 7812 files scanned
check-ci-filter-parity.mjs EXIT 0
check-cross-package-test-inputs.mjs EXIT 0
check-shard-attestation.mjs EXIT 0
check-system-context-census.mjs EXIT 0 + --self-test EXIT 0 (all cases, 6 new)
check-tenant-audit-census.mjs EXIT 0 (cites this file at :77-84; those lines did not move)
bare-root-worklist.mjs --self-test EXIT 0 none stale, none missing, none contradicted
check-test-completeness.mjs NOT MEASURED — "PREREQUISITE NOT MET", exit 3: it grades a
saved turbo test log and no local log exists. Not a red.
check:pm-dispatch-gates EXIT 0 "dispatch-gates self-test: 1179 cases pass."

⚠️check:pm-dispatch-gates needed ~690s on this shared box (it builds temp git repos and
spawns child CLIs), which is past the container's ~10-minute foreground ceiling: two
foreground attempts were killed at 500s and at 520s under the shared verify lock, both with
no output at all. It was then run to completion and its exit code collected inside the same
turn. Recording that, because "killed at the ceiling" and "red" are not the same reading and
the first two attempts would have looked identical to a hang.

Exit codes were captured before any pipe (cmd > file 2>&1; EXIT=$?), and each line above
quotes the gate's own verdict line rather than a bare $?.

Changeset

skip-changeset: the diff is two CI-internal scripts under scripts/, publishes nothing
from any package, and releases nothing — the textbook case lint.yml names in its own
changeset-family comment. The label is applied on this PR.

Generated by Claude Code


Generated by Claude Code

…ually reads
The gate spelled 29 path literals -- the page it maintains and the spec seeds
it cites -- and none of them is its population. `isystem-census.mjs` builds the
census from `git ls-files packages examples`, so a diff that merely SHIFTS a
cited line reds the gate in CI while the dispatch derivation places it in the
`silent` bucket, which reads as a clearance and is not.
Declares `ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**']` using the idiom
`check-tenant-audit-census.mjs` already carries and `check-watch-hint-literal`
already gates, derives the corpus roots from a new `CORPUS_ROOTS` constant in
`isystem-census.mjs`, and pins both directions in the gate's own self-test so a
corpus root added or dropped cannot outrun the declaration.
Measured cost of the wide form: one extra derived family on cards under
`packages/**` / `examples/**` only, against a gate that runs in ~3s and that CI
runs on every PR regardless.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 2, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review September 2, 2026 03:10
@baozhoutao
baozhoutao added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 1f9175eSep 2, 2026
39 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14131-census-population-declaration branch September 2, 2026 03:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Declare the packages/examples census subtree check-system-context-census actually reads - #14323

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration
Sep 2, 2026
Merged

Declare the packages/examples census subtree check-system-context-census actually reads#14323
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration

Conversation

@baozhoutao

@baozhoutaobaozhoutao commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14131

check-system-context-census.mjs spelled 29 path literals — the page it maintains, the
four colliding isSystem declarations, the NON_READ_ANCHORS citations — and not one of
them is its population. isystem-census.mjs builds the census from
git ls-files packages examples, so a diff that merely SHIFTS a cited line reds the gate
in Lint & Repo Gates while the dispatch derivation places it in the silent bucket,
which reads as a clearance and is not.

Measured cost, from this card and its comments: three CI laps plus three repair dispatches
in one night, on three unrelated PRs, each after a dev had honestly run its derived
families and honestly reported green.

Premise re-check on fresh origin/main (a39b02a6b, clean tree) — HOLDS

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack \
--residue packages/metadata-protocol/src/protocol.ts
-> Silent (source names paths, none of which cover yours): 139 famil(ies)
- node scripts/check-system-context-census.mjs [lint.yml] names:
content/docs/permissions/system-context.mdx, packages/spec/src/kernel/execution-context.zod.ts, ...
(3 of 29 declared literals reach nothing tracked)
node scripts/check-system-context-census.mjs # exit captured before any pipe
-> EXIT 0: 109 elevation read sites in 20 packages across 45 files, all anchored;
145 anchors resolve, 27 declared non-read

Every number in the card re-derived unchanged (109 / 20 / 45 / 145). The Silent bucket is
139 today, not the 127 the card recorded — re-derived, not quoted.

Deliverable 1 — the Silent-bucket census, MEASURED

The engine seat's first-deliverable fence: classify the Silent families by "declared
population vs actually-read population". Static classification was tried first and was not
good enough (a recursive walk(dir) hides its seed root), so the population was
measured instead: every one of the 139 Silent families was run under an fs-tracing
preload that records the repo-relative path of every readFileSync / readdirSync /
git ls-files the gate makes, and the trace was compared against the literals
extractWatchHints reads out of that family's own sources.

Definition used, stated so the number is checkable: content reads only
(readFileSync/readFile/openSync/createReadStream) — statSync/existsSync probes
are excluded — of tracked files, minus the 5-path footprint pnpm itself reads.

bucketfamilies
read 20+ tracked files under packages/ or examples/ that no declared literal covers49
read 20+ undeclared tracked files anywhere53
read 1..19 undeclared files83
declaration covers every file read, or nothing tracked was read3
(of the 139, exited non-zero — trace is partial, so these UNDER-count)22

So this card is one member of a class, not a one-gate defect. The top of the list,
undeclared reads after declared literals:

familydeclaredundeclared reads
pnpm check:nul-bytes27815
node scripts/check-closing-keyword-parity.mjs67811
node scripts/check-self-test-workflow-commands.mjs76360
node scripts/check-position-name-fold-loaders.mjs76251
pnpm check:refd-timer-probe55661
node scripts/check-comment-mask-corpus.mjs15661
pnpm check:vendor-version-stamps25660
pnpm check:skill-identifier-liveness175495
pnpm check:parse-guard25449
pnpm check:engine-double-contract15410
node scripts/check-system-context-census.mjs295387
pnpm check:error-code-casing235161
node scripts/check-tenant-audit-census.mjs244177

⚠️ What the number is NOT: reads are an upper bound on the verdict-bearing population.
A gate that opens every package.json to build a workspace list reads far more than can
red it. Four were verified by reading the source — check:engine-double-contract
(SCAN_ROOTS = ['packages', 'examples'], one declared literal),
check:error-code-casing (SCAN_ROOTS = ['packages']), check:route-envelope
(walk(join(ROOT, 'packages'))), check:error-status-conformance (walk(SCAN_ROOT)) —
and all four are the same shape as this card. ⛔ The remaining members are NOT asserted to
each want this repair; three of the largest provably cannot take it (see below).

Already-worked subsets, so nothing here is re-filed:#13519 / PR #14188 repaired four
gates by declaring what they read; #14189 carries the three whole-tree gates
(check:nul-bytes, check-comment-mask-corpus, check:refd-timer-probe) for which a
truthful declaration is "every file" and is therefore refused by the derivation's own
"22 leads is the same as none" rule. The residue between those seven and the 49 measured
here is filed as a new finding (linked from this PR's card comment) — ⛔ not fixed here,
and its derivation-layer half queues behind #14013, which holds
scripts/pm/dispatch-gates.mjs right now.

Deliverable 2 — the family-bloat cost of the wide declaration, MEASURED FIRST

The services seat's fence: ⛔ do not adopt the wide declaration before measuring what it
costs an ordinary diff. Families derived per probe path, before -> after, at a39b02a6b:

probe pathbeforeafter
packages/lint/src/authoring-rules.ts1920
packages/plugins/plugin-auth/src/auth-plugin.ts2223
packages/metadata-protocol/src/protocol.ts2122
packages/spec/src/data/object.zod.ts4242 (already named — it is a declared literal)
examples/app-crm/package.json1718
content/docs/permissions/access-matrix.mdx3030
scripts/check-nul-bytes.mjs1414
.github/workflows/lint.yml2323

+1 family, and only on cards under the two declared subtrees. Nothing outside them
moves. The gate it adds runs in ~3s and CI runs it on every PR regardless, so the local
cost is one command against the CI lap it replaces. That is the measurement the services
seat asked for, and it is what carries the decision below.

The declaration shipped: WIDE

ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**'], the idiom
check-tenant-audit-census.mjs:146 already carries and check-watch-hint-literal already
gates. ⛔ No second pattern invented.

Narrow (the 20 packages / 45 files that carry a read site today) was considered and
refused on the gate's own terms: a roster of the files that carry a read site TODAY can
never name the file that grows one TOMORROW, and a NEW read site is exactly what check B
— the mandatory POPULATION half — exists to catch. A narrow declaration derives green for
the one case that most needs the lead, so it re-introduces this defect wearing the shape
of a fix. The services seat leaned the same way; the measurement above is what made it a
decision rather than a preference.

What holds the declaration honest

isystem-census.mjs now names its corpus roots once (CORPUS_ROOTS), collectCorpus
walks that constant, and the gate's --self-test derives both directions from it:
every walked root is declared, and no declared root is unwalked. A corpus root added or
dropped reds here instead of silently outrunning the declaration.

Reverse verification (both mutations on the committed tree, both legs restored)

Predicted direction: RED, plus the derivation dropping the gate.

MUTATION A the computed spelling ROOT_DIR_WATCH_HINTS = CORPUS_ROOTS.map(...)
on-disk proof: literal line 1 -> 0, computed line present, blob da3189a39 != HEAD 804912155
self-test EXIT 1 "declared exactly once, as an array of quoted literals"
check-watch-hint-literal EXIT 1 "the declaration is COMPUTED, not a literal array"
derivation for packages/lint/src/authoring-rules.ts 20 -> 19, census named: NO
MUTATION B drop one walked root ROOT_DIR_WATCH_HINTS = ['packages/**']
on-disk proof: new line present, old line absent, blob c44b2c2b4 != HEAD
self-test EXIT 1 "every root the census walks is declared"
restore (git checkout HEAD -- path, absolute, trap-guarded): git diff HEAD EMPTY and
hash-object == HEAD blob 804912155 after BOTH legs; post-restore self-test EXIT 0

Mutation A is the load-bearing one: identical runtime value, every runtime assertion still
green, and zero hints extracted — the measured proof that the literal spelling is what
carries this fix.

Checks run — union at 03edd9ce5 (the final commit of this branch)

Derived for the real changeset with node scripts/pm/dispatch-gates.mjs (no paths — the
script takes the change set off the merge base itself): 16 families, 14 by path + 2 by
change kind.

check:agent-test-spelling EXIT 0
check:bash32-floor EXIT 0
check:cli-command-ids EXIT 0
check:cross-package-test-inputs EXIT 0
check:entry-guard EXIT 0
check:parse-guard EXIT 0
check:pnpm-filter-targets EXIT 0
check:ratchet-remedy-authority EXIT 0 (named in the dispatch)
check:watch-hint-literal EXIT 0 43 declarations, ROOT_DIR_WATCH_HINTS 29
check:declared-population-live EXIT 0 156 of 200 families declare a live population
check:nul-bytes EXIT 0 7812 files scanned
check-ci-filter-parity.mjs EXIT 0
check-cross-package-test-inputs.mjs EXIT 0
check-shard-attestation.mjs EXIT 0
check-system-context-census.mjs EXIT 0 + --self-test EXIT 0 (all cases, 6 new)
check-tenant-audit-census.mjs EXIT 0 (cites this file at :77-84; those lines did not move)
bare-root-worklist.mjs --self-test EXIT 0 none stale, none missing, none contradicted
check-test-completeness.mjs NOT MEASURED — "PREREQUISITE NOT MET", exit 3: it grades a
saved turbo test log and no local log exists. Not a red.
check:pm-dispatch-gates EXIT 0 "dispatch-gates self-test: 1179 cases pass."

⚠️check:pm-dispatch-gates needed ~690s on this shared box (it builds temp git repos and
spawns child CLIs), which is past the container's ~10-minute foreground ceiling: two
foreground attempts were killed at 500s and at 520s under the shared verify lock, both with
no output at all. It was then run to completion and its exit code collected inside the same
turn. Recording that, because "killed at the ceiling" and "red" are not the same reading and
the first two attempts would have looked identical to a hang.

Exit codes were captured before any pipe (cmd > file 2>&1; EXIT=$?), and each line above
quotes the gate's own verdict line rather than a bare $?.

Changeset

skip-changeset: the diff is two CI-internal scripts under scripts/, publishes nothing
from any package, and releases nothing — the textbook case lint.yml names in its own
changeset-family comment. The label is applied on this PR.

Generated by Claude Code


Generated by Claude Code

…ually reads
The gate spelled 29 path literals -- the page it maintains and the spec seeds
it cites -- and none of them is its population. `isystem-census.mjs` builds the
census from `git ls-files packages examples`, so a diff that merely SHIFTS a
cited line reds the gate in CI while the dispatch derivation places it in the
`silent` bucket, which reads as a clearance and is not.
Declares `ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**']` using the idiom
`check-tenant-audit-census.mjs` already carries and `check-watch-hint-literal`
already gates, derives the corpus roots from a new `CORPUS_ROOTS` constant in
`isystem-census.mjs`, and pins both directions in the gate's own self-test so a
corpus root added or dropped cannot outrun the declaration.
Measured cost of the wide form: one extra derived family on cards under
`packages/**` / `examples/**` only, against a gate that runs in ~3s and that CI
runs on every PR regardless.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 2, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review September 2, 2026 03:10
@baozhoutao
baozhoutao added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 1f9175eSep 2, 2026
39 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14131-census-population-declaration branch September 2, 2026 03:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Declare the packages/examples census subtree check-system-context-census actually reads - #14323

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration
Sep 2, 2026
Merged

Declare the packages/examples census subtree check-system-context-census actually reads#14323
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration

Conversation

@baozhoutao

@baozhoutaobaozhoutao commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14131

check-system-context-census.mjs spelled 29 path literals — the page it maintains, the
four colliding isSystem declarations, the NON_READ_ANCHORS citations — and not one of
them is its population. isystem-census.mjs builds the census from
git ls-files packages examples, so a diff that merely SHIFTS a cited line reds the gate
in Lint & Repo Gates while the dispatch derivation places it in the silent bucket,
which reads as a clearance and is not.

Measured cost, from this card and its comments: three CI laps plus three repair dispatches
in one night, on three unrelated PRs, each after a dev had honestly run its derived
families and honestly reported green.

Premise re-check on fresh origin/main (a39b02a6b, clean tree) — HOLDS

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack \
--residue packages/metadata-protocol/src/protocol.ts
-> Silent (source names paths, none of which cover yours): 139 famil(ies)
- node scripts/check-system-context-census.mjs [lint.yml] names:
content/docs/permissions/system-context.mdx, packages/spec/src/kernel/execution-context.zod.ts, ...
(3 of 29 declared literals reach nothing tracked)
node scripts/check-system-context-census.mjs # exit captured before any pipe
-> EXIT 0: 109 elevation read sites in 20 packages across 45 files, all anchored;
145 anchors resolve, 27 declared non-read

Every number in the card re-derived unchanged (109 / 20 / 45 / 145). The Silent bucket is
139 today, not the 127 the card recorded — re-derived, not quoted.

Deliverable 1 — the Silent-bucket census, MEASURED

The engine seat's first-deliverable fence: classify the Silent families by "declared
population vs actually-read population". Static classification was tried first and was not
good enough (a recursive walk(dir) hides its seed root), so the population was
measured instead: every one of the 139 Silent families was run under an fs-tracing
preload that records the repo-relative path of every readFileSync / readdirSync /
git ls-files the gate makes, and the trace was compared against the literals
extractWatchHints reads out of that family's own sources.

Definition used, stated so the number is checkable: content reads only
(readFileSync/readFile/openSync/createReadStream) — statSync/existsSync probes
are excluded — of tracked files, minus the 5-path footprint pnpm itself reads.

bucketfamilies
read 20+ tracked files under packages/ or examples/ that no declared literal covers49
read 20+ undeclared tracked files anywhere53
read 1..19 undeclared files83
declaration covers every file read, or nothing tracked was read3
(of the 139, exited non-zero — trace is partial, so these UNDER-count)22

So this card is one member of a class, not a one-gate defect. The top of the list,
undeclared reads after declared literals:

familydeclaredundeclared reads
pnpm check:nul-bytes27815
node scripts/check-closing-keyword-parity.mjs67811
node scripts/check-self-test-workflow-commands.mjs76360
node scripts/check-position-name-fold-loaders.mjs76251
pnpm check:refd-timer-probe55661
node scripts/check-comment-mask-corpus.mjs15661
pnpm check:vendor-version-stamps25660
pnpm check:skill-identifier-liveness175495
pnpm check:parse-guard25449
pnpm check:engine-double-contract15410
node scripts/check-system-context-census.mjs295387
pnpm check:error-code-casing235161
node scripts/check-tenant-audit-census.mjs244177

⚠️ What the number is NOT: reads are an upper bound on the verdict-bearing population.
A gate that opens every package.json to build a workspace list reads far more than can
red it. Four were verified by reading the source — check:engine-double-contract
(SCAN_ROOTS = ['packages', 'examples'], one declared literal),
check:error-code-casing (SCAN_ROOTS = ['packages']), check:route-envelope
(walk(join(ROOT, 'packages'))), check:error-status-conformance (walk(SCAN_ROOT)) —
and all four are the same shape as this card. ⛔ The remaining members are NOT asserted to
each want this repair; three of the largest provably cannot take it (see below).

Already-worked subsets, so nothing here is re-filed:#13519 / PR #14188 repaired four
gates by declaring what they read; #14189 carries the three whole-tree gates
(check:nul-bytes, check-comment-mask-corpus, check:refd-timer-probe) for which a
truthful declaration is "every file" and is therefore refused by the derivation's own
"22 leads is the same as none" rule. The residue between those seven and the 49 measured
here is filed as a new finding (linked from this PR's card comment) — ⛔ not fixed here,
and its derivation-layer half queues behind #14013, which holds
scripts/pm/dispatch-gates.mjs right now.

Deliverable 2 — the family-bloat cost of the wide declaration, MEASURED FIRST

The services seat's fence: ⛔ do not adopt the wide declaration before measuring what it
costs an ordinary diff. Families derived per probe path, before -> after, at a39b02a6b:

probe pathbeforeafter
packages/lint/src/authoring-rules.ts1920
packages/plugins/plugin-auth/src/auth-plugin.ts2223
packages/metadata-protocol/src/protocol.ts2122
packages/spec/src/data/object.zod.ts4242 (already named — it is a declared literal)
examples/app-crm/package.json1718
content/docs/permissions/access-matrix.mdx3030
scripts/check-nul-bytes.mjs1414
.github/workflows/lint.yml2323

+1 family, and only on cards under the two declared subtrees. Nothing outside them
moves. The gate it adds runs in ~3s and CI runs it on every PR regardless, so the local
cost is one command against the CI lap it replaces. That is the measurement the services
seat asked for, and it is what carries the decision below.

The declaration shipped: WIDE

ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**'], the idiom
check-tenant-audit-census.mjs:146 already carries and check-watch-hint-literal already
gates. ⛔ No second pattern invented.

Narrow (the 20 packages / 45 files that carry a read site today) was considered and
refused on the gate's own terms: a roster of the files that carry a read site TODAY can
never name the file that grows one TOMORROW, and a NEW read site is exactly what check B
— the mandatory POPULATION half — exists to catch. A narrow declaration derives green for
the one case that most needs the lead, so it re-introduces this defect wearing the shape
of a fix. The services seat leaned the same way; the measurement above is what made it a
decision rather than a preference.

What holds the declaration honest

isystem-census.mjs now names its corpus roots once (CORPUS_ROOTS), collectCorpus
walks that constant, and the gate's --self-test derives both directions from it:
every walked root is declared, and no declared root is unwalked. A corpus root added or
dropped reds here instead of silently outrunning the declaration.

Reverse verification (both mutations on the committed tree, both legs restored)

Predicted direction: RED, plus the derivation dropping the gate.

MUTATION A the computed spelling ROOT_DIR_WATCH_HINTS = CORPUS_ROOTS.map(...)
on-disk proof: literal line 1 -> 0, computed line present, blob da3189a39 != HEAD 804912155
self-test EXIT 1 "declared exactly once, as an array of quoted literals"
check-watch-hint-literal EXIT 1 "the declaration is COMPUTED, not a literal array"
derivation for packages/lint/src/authoring-rules.ts 20 -> 19, census named: NO
MUTATION B drop one walked root ROOT_DIR_WATCH_HINTS = ['packages/**']
on-disk proof: new line present, old line absent, blob c44b2c2b4 != HEAD
self-test EXIT 1 "every root the census walks is declared"
restore (git checkout HEAD -- path, absolute, trap-guarded): git diff HEAD EMPTY and
hash-object == HEAD blob 804912155 after BOTH legs; post-restore self-test EXIT 0

Mutation A is the load-bearing one: identical runtime value, every runtime assertion still
green, and zero hints extracted — the measured proof that the literal spelling is what
carries this fix.

Checks run — union at 03edd9ce5 (the final commit of this branch)

Derived for the real changeset with node scripts/pm/dispatch-gates.mjs (no paths — the
script takes the change set off the merge base itself): 16 families, 14 by path + 2 by
change kind.

check:agent-test-spelling EXIT 0
check:bash32-floor EXIT 0
check:cli-command-ids EXIT 0
check:cross-package-test-inputs EXIT 0
check:entry-guard EXIT 0
check:parse-guard EXIT 0
check:pnpm-filter-targets EXIT 0
check:ratchet-remedy-authority EXIT 0 (named in the dispatch)
check:watch-hint-literal EXIT 0 43 declarations, ROOT_DIR_WATCH_HINTS 29
check:declared-population-live EXIT 0 156 of 200 families declare a live population
check:nul-bytes EXIT 0 7812 files scanned
check-ci-filter-parity.mjs EXIT 0
check-cross-package-test-inputs.mjs EXIT 0
check-shard-attestation.mjs EXIT 0
check-system-context-census.mjs EXIT 0 + --self-test EXIT 0 (all cases, 6 new)
check-tenant-audit-census.mjs EXIT 0 (cites this file at :77-84; those lines did not move)
bare-root-worklist.mjs --self-test EXIT 0 none stale, none missing, none contradicted
check-test-completeness.mjs NOT MEASURED — "PREREQUISITE NOT MET", exit 3: it grades a
saved turbo test log and no local log exists. Not a red.
check:pm-dispatch-gates EXIT 0 "dispatch-gates self-test: 1179 cases pass."

⚠️check:pm-dispatch-gates needed ~690s on this shared box (it builds temp git repos and
spawns child CLIs), which is past the container's ~10-minute foreground ceiling: two
foreground attempts were killed at 500s and at 520s under the shared verify lock, both with
no output at all. It was then run to completion and its exit code collected inside the same
turn. Recording that, because "killed at the ceiling" and "red" are not the same reading and
the first two attempts would have looked identical to a hang.

Exit codes were captured before any pipe (cmd > file 2>&1; EXIT=$?), and each line above
quotes the gate's own verdict line rather than a bare $?.

Changeset

skip-changeset: the diff is two CI-internal scripts under scripts/, publishes nothing
from any package, and releases nothing — the textbook case lint.yml names in its own
changeset-family comment. The label is applied on this PR.

Generated by Claude Code


Generated by Claude Code

…ually reads
The gate spelled 29 path literals -- the page it maintains and the spec seeds
it cites -- and none of them is its population. `isystem-census.mjs` builds the
census from `git ls-files packages examples`, so a diff that merely SHIFTS a
cited line reds the gate in CI while the dispatch derivation places it in the
`silent` bucket, which reads as a clearance and is not.
Declares `ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**']` using the idiom
`check-tenant-audit-census.mjs` already carries and `check-watch-hint-literal`
already gates, derives the corpus roots from a new `CORPUS_ROOTS` constant in
`isystem-census.mjs`, and pins both directions in the gate's own self-test so a
corpus root added or dropped cannot outrun the declaration.
Measured cost of the wide form: one extra derived family on cards under
`packages/**` / `examples/**` only, against a gate that runs in ~3s and that CI
runs on every PR regardless.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 2, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review September 2, 2026 03:10
@baozhoutao
baozhoutao added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 1f9175eSep 2, 2026
39 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14131-census-population-declaration branch September 2, 2026 03:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Declare the packages/examples census subtree check-system-context-census actually reads - #14323

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration
Sep 2, 2026
Merged

Declare the packages/examples census subtree check-system-context-census actually reads#14323
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration

Conversation

@baozhoutao

@baozhoutaobaozhoutao commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14131

check-system-context-census.mjs spelled 29 path literals — the page it maintains, the
four colliding isSystem declarations, the NON_READ_ANCHORS citations — and not one of
them is its population. isystem-census.mjs builds the census from
git ls-files packages examples, so a diff that merely SHIFTS a cited line reds the gate
in Lint & Repo Gates while the dispatch derivation places it in the silent bucket,
which reads as a clearance and is not.

Measured cost, from this card and its comments: three CI laps plus three repair dispatches
in one night, on three unrelated PRs, each after a dev had honestly run its derived
families and honestly reported green.

Premise re-check on fresh origin/main (a39b02a6b, clean tree) — HOLDS

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack \
--residue packages/metadata-protocol/src/protocol.ts
-> Silent (source names paths, none of which cover yours): 139 famil(ies)
- node scripts/check-system-context-census.mjs [lint.yml] names:
content/docs/permissions/system-context.mdx, packages/spec/src/kernel/execution-context.zod.ts, ...
(3 of 29 declared literals reach nothing tracked)
node scripts/check-system-context-census.mjs # exit captured before any pipe
-> EXIT 0: 109 elevation read sites in 20 packages across 45 files, all anchored;
145 anchors resolve, 27 declared non-read

Every number in the card re-derived unchanged (109 / 20 / 45 / 145). The Silent bucket is
139 today, not the 127 the card recorded — re-derived, not quoted.

Deliverable 1 — the Silent-bucket census, MEASURED

The engine seat's first-deliverable fence: classify the Silent families by "declared
population vs actually-read population". Static classification was tried first and was not
good enough (a recursive walk(dir) hides its seed root), so the population was
measured instead: every one of the 139 Silent families was run under an fs-tracing
preload that records the repo-relative path of every readFileSync / readdirSync /
git ls-files the gate makes, and the trace was compared against the literals
extractWatchHints reads out of that family's own sources.

Definition used, stated so the number is checkable: content reads only
(readFileSync/readFile/openSync/createReadStream) — statSync/existsSync probes
are excluded — of tracked files, minus the 5-path footprint pnpm itself reads.

bucketfamilies
read 20+ tracked files under packages/ or examples/ that no declared literal covers49
read 20+ undeclared tracked files anywhere53
read 1..19 undeclared files83
declaration covers every file read, or nothing tracked was read3
(of the 139, exited non-zero — trace is partial, so these UNDER-count)22

So this card is one member of a class, not a one-gate defect. The top of the list,
undeclared reads after declared literals:

familydeclaredundeclared reads
pnpm check:nul-bytes27815
node scripts/check-closing-keyword-parity.mjs67811
node scripts/check-self-test-workflow-commands.mjs76360
node scripts/check-position-name-fold-loaders.mjs76251
pnpm check:refd-timer-probe55661
node scripts/check-comment-mask-corpus.mjs15661
pnpm check:vendor-version-stamps25660
pnpm check:skill-identifier-liveness175495
pnpm check:parse-guard25449
pnpm check:engine-double-contract15410
node scripts/check-system-context-census.mjs295387
pnpm check:error-code-casing235161
node scripts/check-tenant-audit-census.mjs244177

⚠️ What the number is NOT: reads are an upper bound on the verdict-bearing population.
A gate that opens every package.json to build a workspace list reads far more than can
red it. Four were verified by reading the source — check:engine-double-contract
(SCAN_ROOTS = ['packages', 'examples'], one declared literal),
check:error-code-casing (SCAN_ROOTS = ['packages']), check:route-envelope
(walk(join(ROOT, 'packages'))), check:error-status-conformance (walk(SCAN_ROOT)) —
and all four are the same shape as this card. ⛔ The remaining members are NOT asserted to
each want this repair; three of the largest provably cannot take it (see below).

Already-worked subsets, so nothing here is re-filed:#13519 / PR #14188 repaired four
gates by declaring what they read; #14189 carries the three whole-tree gates
(check:nul-bytes, check-comment-mask-corpus, check:refd-timer-probe) for which a
truthful declaration is "every file" and is therefore refused by the derivation's own
"22 leads is the same as none" rule. The residue between those seven and the 49 measured
here is filed as a new finding (linked from this PR's card comment) — ⛔ not fixed here,
and its derivation-layer half queues behind #14013, which holds
scripts/pm/dispatch-gates.mjs right now.

Deliverable 2 — the family-bloat cost of the wide declaration, MEASURED FIRST

The services seat's fence: ⛔ do not adopt the wide declaration before measuring what it
costs an ordinary diff. Families derived per probe path, before -> after, at a39b02a6b:

probe pathbeforeafter
packages/lint/src/authoring-rules.ts1920
packages/plugins/plugin-auth/src/auth-plugin.ts2223
packages/metadata-protocol/src/protocol.ts2122
packages/spec/src/data/object.zod.ts4242 (already named — it is a declared literal)
examples/app-crm/package.json1718
content/docs/permissions/access-matrix.mdx3030
scripts/check-nul-bytes.mjs1414
.github/workflows/lint.yml2323

+1 family, and only on cards under the two declared subtrees. Nothing outside them
moves. The gate it adds runs in ~3s and CI runs it on every PR regardless, so the local
cost is one command against the CI lap it replaces. That is the measurement the services
seat asked for, and it is what carries the decision below.

The declaration shipped: WIDE

ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**'], the idiom
check-tenant-audit-census.mjs:146 already carries and check-watch-hint-literal already
gates. ⛔ No second pattern invented.

Narrow (the 20 packages / 45 files that carry a read site today) was considered and
refused on the gate's own terms: a roster of the files that carry a read site TODAY can
never name the file that grows one TOMORROW, and a NEW read site is exactly what check B
— the mandatory POPULATION half — exists to catch. A narrow declaration derives green for
the one case that most needs the lead, so it re-introduces this defect wearing the shape
of a fix. The services seat leaned the same way; the measurement above is what made it a
decision rather than a preference.

What holds the declaration honest

isystem-census.mjs now names its corpus roots once (CORPUS_ROOTS), collectCorpus
walks that constant, and the gate's --self-test derives both directions from it:
every walked root is declared, and no declared root is unwalked. A corpus root added or
dropped reds here instead of silently outrunning the declaration.

Reverse verification (both mutations on the committed tree, both legs restored)

Predicted direction: RED, plus the derivation dropping the gate.

MUTATION A the computed spelling ROOT_DIR_WATCH_HINTS = CORPUS_ROOTS.map(...)
on-disk proof: literal line 1 -> 0, computed line present, blob da3189a39 != HEAD 804912155
self-test EXIT 1 "declared exactly once, as an array of quoted literals"
check-watch-hint-literal EXIT 1 "the declaration is COMPUTED, not a literal array"
derivation for packages/lint/src/authoring-rules.ts 20 -> 19, census named: NO
MUTATION B drop one walked root ROOT_DIR_WATCH_HINTS = ['packages/**']
on-disk proof: new line present, old line absent, blob c44b2c2b4 != HEAD
self-test EXIT 1 "every root the census walks is declared"
restore (git checkout HEAD -- path, absolute, trap-guarded): git diff HEAD EMPTY and
hash-object == HEAD blob 804912155 after BOTH legs; post-restore self-test EXIT 0

Mutation A is the load-bearing one: identical runtime value, every runtime assertion still
green, and zero hints extracted — the measured proof that the literal spelling is what
carries this fix.

Checks run — union at 03edd9ce5 (the final commit of this branch)

Derived for the real changeset with node scripts/pm/dispatch-gates.mjs (no paths — the
script takes the change set off the merge base itself): 16 families, 14 by path + 2 by
change kind.

check:agent-test-spelling EXIT 0
check:bash32-floor EXIT 0
check:cli-command-ids EXIT 0
check:cross-package-test-inputs EXIT 0
check:entry-guard EXIT 0
check:parse-guard EXIT 0
check:pnpm-filter-targets EXIT 0
check:ratchet-remedy-authority EXIT 0 (named in the dispatch)
check:watch-hint-literal EXIT 0 43 declarations, ROOT_DIR_WATCH_HINTS 29
check:declared-population-live EXIT 0 156 of 200 families declare a live population
check:nul-bytes EXIT 0 7812 files scanned
check-ci-filter-parity.mjs EXIT 0
check-cross-package-test-inputs.mjs EXIT 0
check-shard-attestation.mjs EXIT 0
check-system-context-census.mjs EXIT 0 + --self-test EXIT 0 (all cases, 6 new)
check-tenant-audit-census.mjs EXIT 0 (cites this file at :77-84; those lines did not move)
bare-root-worklist.mjs --self-test EXIT 0 none stale, none missing, none contradicted
check-test-completeness.mjs NOT MEASURED — "PREREQUISITE NOT MET", exit 3: it grades a
saved turbo test log and no local log exists. Not a red.
check:pm-dispatch-gates EXIT 0 "dispatch-gates self-test: 1179 cases pass."

⚠️check:pm-dispatch-gates needed ~690s on this shared box (it builds temp git repos and
spawns child CLIs), which is past the container's ~10-minute foreground ceiling: two
foreground attempts were killed at 500s and at 520s under the shared verify lock, both with
no output at all. It was then run to completion and its exit code collected inside the same
turn. Recording that, because "killed at the ceiling" and "red" are not the same reading and
the first two attempts would have looked identical to a hang.

Exit codes were captured before any pipe (cmd > file 2>&1; EXIT=$?), and each line above
quotes the gate's own verdict line rather than a bare $?.

Changeset

skip-changeset: the diff is two CI-internal scripts under scripts/, publishes nothing
from any package, and releases nothing — the textbook case lint.yml names in its own
changeset-family comment. The label is applied on this PR.

Generated by Claude Code


Generated by Claude Code

…ually reads
The gate spelled 29 path literals -- the page it maintains and the spec seeds
it cites -- and none of them is its population. `isystem-census.mjs` builds the
census from `git ls-files packages examples`, so a diff that merely SHIFTS a
cited line reds the gate in CI while the dispatch derivation places it in the
`silent` bucket, which reads as a clearance and is not.
Declares `ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**']` using the idiom
`check-tenant-audit-census.mjs` already carries and `check-watch-hint-literal`
already gates, derives the corpus roots from a new `CORPUS_ROOTS` constant in
`isystem-census.mjs`, and pins both directions in the gate's own self-test so a
corpus root added or dropped cannot outrun the declaration.
Measured cost of the wide form: one extra derived family on cards under
`packages/**` / `examples/**` only, against a gate that runs in ~3s and that CI
runs on every PR regardless.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 2, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review September 2, 2026 03:10
@baozhoutao
baozhoutao added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 1f9175eSep 2, 2026
39 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14131-census-population-declaration branch September 2, 2026 03:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Declare the packages/examples census subtree check-system-context-census actually reads - #14323

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration
Sep 2, 2026
Merged

Declare the packages/examples census subtree check-system-context-census actually reads#14323
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration

Conversation

@baozhoutao

@baozhoutaobaozhoutao commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14131

check-system-context-census.mjs spelled 29 path literals — the page it maintains, the
four colliding isSystem declarations, the NON_READ_ANCHORS citations — and not one of
them is its population. isystem-census.mjs builds the census from
git ls-files packages examples, so a diff that merely SHIFTS a cited line reds the gate
in Lint & Repo Gates while the dispatch derivation places it in the silent bucket,
which reads as a clearance and is not.

Measured cost, from this card and its comments: three CI laps plus three repair dispatches
in one night, on three unrelated PRs, each after a dev had honestly run its derived
families and honestly reported green.

Premise re-check on fresh origin/main (a39b02a6b, clean tree) — HOLDS

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack \
--residue packages/metadata-protocol/src/protocol.ts
-> Silent (source names paths, none of which cover yours): 139 famil(ies)
- node scripts/check-system-context-census.mjs [lint.yml] names:
content/docs/permissions/system-context.mdx, packages/spec/src/kernel/execution-context.zod.ts, ...
(3 of 29 declared literals reach nothing tracked)
node scripts/check-system-context-census.mjs # exit captured before any pipe
-> EXIT 0: 109 elevation read sites in 20 packages across 45 files, all anchored;
145 anchors resolve, 27 declared non-read

Every number in the card re-derived unchanged (109 / 20 / 45 / 145). The Silent bucket is
139 today, not the 127 the card recorded — re-derived, not quoted.

Deliverable 1 — the Silent-bucket census, MEASURED

The engine seat's first-deliverable fence: classify the Silent families by "declared
population vs actually-read population". Static classification was tried first and was not
good enough (a recursive walk(dir) hides its seed root), so the population was
measured instead: every one of the 139 Silent families was run under an fs-tracing
preload that records the repo-relative path of every readFileSync / readdirSync /
git ls-files the gate makes, and the trace was compared against the literals
extractWatchHints reads out of that family's own sources.

Definition used, stated so the number is checkable: content reads only
(readFileSync/readFile/openSync/createReadStream) — statSync/existsSync probes
are excluded — of tracked files, minus the 5-path footprint pnpm itself reads.

bucketfamilies
read 20+ tracked files under packages/ or examples/ that no declared literal covers49
read 20+ undeclared tracked files anywhere53
read 1..19 undeclared files83
declaration covers every file read, or nothing tracked was read3
(of the 139, exited non-zero — trace is partial, so these UNDER-count)22

So this card is one member of a class, not a one-gate defect. The top of the list,
undeclared reads after declared literals:

familydeclaredundeclared reads
pnpm check:nul-bytes27815
node scripts/check-closing-keyword-parity.mjs67811
node scripts/check-self-test-workflow-commands.mjs76360
node scripts/check-position-name-fold-loaders.mjs76251
pnpm check:refd-timer-probe55661
node scripts/check-comment-mask-corpus.mjs15661
pnpm check:vendor-version-stamps25660
pnpm check:skill-identifier-liveness175495
pnpm check:parse-guard25449
pnpm check:engine-double-contract15410
node scripts/check-system-context-census.mjs295387
pnpm check:error-code-casing235161
node scripts/check-tenant-audit-census.mjs244177

⚠️ What the number is NOT: reads are an upper bound on the verdict-bearing population.
A gate that opens every package.json to build a workspace list reads far more than can
red it. Four were verified by reading the source — check:engine-double-contract
(SCAN_ROOTS = ['packages', 'examples'], one declared literal),
check:error-code-casing (SCAN_ROOTS = ['packages']), check:route-envelope
(walk(join(ROOT, 'packages'))), check:error-status-conformance (walk(SCAN_ROOT)) —
and all four are the same shape as this card. ⛔ The remaining members are NOT asserted to
each want this repair; three of the largest provably cannot take it (see below).

Already-worked subsets, so nothing here is re-filed:#13519 / PR #14188 repaired four
gates by declaring what they read; #14189 carries the three whole-tree gates
(check:nul-bytes, check-comment-mask-corpus, check:refd-timer-probe) for which a
truthful declaration is "every file" and is therefore refused by the derivation's own
"22 leads is the same as none" rule. The residue between those seven and the 49 measured
here is filed as a new finding (linked from this PR's card comment) — ⛔ not fixed here,
and its derivation-layer half queues behind #14013, which holds
scripts/pm/dispatch-gates.mjs right now.

Deliverable 2 — the family-bloat cost of the wide declaration, MEASURED FIRST

The services seat's fence: ⛔ do not adopt the wide declaration before measuring what it
costs an ordinary diff. Families derived per probe path, before -> after, at a39b02a6b:

probe pathbeforeafter
packages/lint/src/authoring-rules.ts1920
packages/plugins/plugin-auth/src/auth-plugin.ts2223
packages/metadata-protocol/src/protocol.ts2122
packages/spec/src/data/object.zod.ts4242 (already named — it is a declared literal)
examples/app-crm/package.json1718
content/docs/permissions/access-matrix.mdx3030
scripts/check-nul-bytes.mjs1414
.github/workflows/lint.yml2323

+1 family, and only on cards under the two declared subtrees. Nothing outside them
moves. The gate it adds runs in ~3s and CI runs it on every PR regardless, so the local
cost is one command against the CI lap it replaces. That is the measurement the services
seat asked for, and it is what carries the decision below.

The declaration shipped: WIDE

ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**'], the idiom
check-tenant-audit-census.mjs:146 already carries and check-watch-hint-literal already
gates. ⛔ No second pattern invented.

Narrow (the 20 packages / 45 files that carry a read site today) was considered and
refused on the gate's own terms: a roster of the files that carry a read site TODAY can
never name the file that grows one TOMORROW, and a NEW read site is exactly what check B
— the mandatory POPULATION half — exists to catch. A narrow declaration derives green for
the one case that most needs the lead, so it re-introduces this defect wearing the shape
of a fix. The services seat leaned the same way; the measurement above is what made it a
decision rather than a preference.

What holds the declaration honest

isystem-census.mjs now names its corpus roots once (CORPUS_ROOTS), collectCorpus
walks that constant, and the gate's --self-test derives both directions from it:
every walked root is declared, and no declared root is unwalked. A corpus root added or
dropped reds here instead of silently outrunning the declaration.

Reverse verification (both mutations on the committed tree, both legs restored)

Predicted direction: RED, plus the derivation dropping the gate.

MUTATION A the computed spelling ROOT_DIR_WATCH_HINTS = CORPUS_ROOTS.map(...)
on-disk proof: literal line 1 -> 0, computed line present, blob da3189a39 != HEAD 804912155
self-test EXIT 1 "declared exactly once, as an array of quoted literals"
check-watch-hint-literal EXIT 1 "the declaration is COMPUTED, not a literal array"
derivation for packages/lint/src/authoring-rules.ts 20 -> 19, census named: NO
MUTATION B drop one walked root ROOT_DIR_WATCH_HINTS = ['packages/**']
on-disk proof: new line present, old line absent, blob c44b2c2b4 != HEAD
self-test EXIT 1 "every root the census walks is declared"
restore (git checkout HEAD -- path, absolute, trap-guarded): git diff HEAD EMPTY and
hash-object == HEAD blob 804912155 after BOTH legs; post-restore self-test EXIT 0

Mutation A is the load-bearing one: identical runtime value, every runtime assertion still
green, and zero hints extracted — the measured proof that the literal spelling is what
carries this fix.

Checks run — union at 03edd9ce5 (the final commit of this branch)

Derived for the real changeset with node scripts/pm/dispatch-gates.mjs (no paths — the
script takes the change set off the merge base itself): 16 families, 14 by path + 2 by
change kind.

check:agent-test-spelling EXIT 0
check:bash32-floor EXIT 0
check:cli-command-ids EXIT 0
check:cross-package-test-inputs EXIT 0
check:entry-guard EXIT 0
check:parse-guard EXIT 0
check:pnpm-filter-targets EXIT 0
check:ratchet-remedy-authority EXIT 0 (named in the dispatch)
check:watch-hint-literal EXIT 0 43 declarations, ROOT_DIR_WATCH_HINTS 29
check:declared-population-live EXIT 0 156 of 200 families declare a live population
check:nul-bytes EXIT 0 7812 files scanned
check-ci-filter-parity.mjs EXIT 0
check-cross-package-test-inputs.mjs EXIT 0
check-shard-attestation.mjs EXIT 0
check-system-context-census.mjs EXIT 0 + --self-test EXIT 0 (all cases, 6 new)
check-tenant-audit-census.mjs EXIT 0 (cites this file at :77-84; those lines did not move)
bare-root-worklist.mjs --self-test EXIT 0 none stale, none missing, none contradicted
check-test-completeness.mjs NOT MEASURED — "PREREQUISITE NOT MET", exit 3: it grades a
saved turbo test log and no local log exists. Not a red.
check:pm-dispatch-gates EXIT 0 "dispatch-gates self-test: 1179 cases pass."

⚠️check:pm-dispatch-gates needed ~690s on this shared box (it builds temp git repos and
spawns child CLIs), which is past the container's ~10-minute foreground ceiling: two
foreground attempts were killed at 500s and at 520s under the shared verify lock, both with
no output at all. It was then run to completion and its exit code collected inside the same
turn. Recording that, because "killed at the ceiling" and "red" are not the same reading and
the first two attempts would have looked identical to a hang.

Exit codes were captured before any pipe (cmd > file 2>&1; EXIT=$?), and each line above
quotes the gate's own verdict line rather than a bare $?.

Changeset

skip-changeset: the diff is two CI-internal scripts under scripts/, publishes nothing
from any package, and releases nothing — the textbook case lint.yml names in its own
changeset-family comment. The label is applied on this PR.

Generated by Claude Code


Generated by Claude Code

…ually reads
The gate spelled 29 path literals -- the page it maintains and the spec seeds
it cites -- and none of them is its population. `isystem-census.mjs` builds the
census from `git ls-files packages examples`, so a diff that merely SHIFTS a
cited line reds the gate in CI while the dispatch derivation places it in the
`silent` bucket, which reads as a clearance and is not.
Declares `ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**']` using the idiom
`check-tenant-audit-census.mjs` already carries and `check-watch-hint-literal`
already gates, derives the corpus roots from a new `CORPUS_ROOTS` constant in
`isystem-census.mjs`, and pins both directions in the gate's own self-test so a
corpus root added or dropped cannot outrun the declaration.
Measured cost of the wide form: one extra derived family on cards under
`packages/**` / `examples/**` only, against a gate that runs in ~3s and that CI
runs on every PR regardless.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 2, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review September 2, 2026 03:10
@baozhoutao
baozhoutao added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 1f9175eSep 2, 2026
39 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14131-census-population-declaration branch September 2, 2026 03:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Declare the packages/examples census subtree check-system-context-census actually reads - #14323

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration
Sep 2, 2026
Merged

Declare the packages/examples census subtree check-system-context-census actually reads#14323
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration

Conversation

@baozhoutao

@baozhoutaobaozhoutao commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14131

check-system-context-census.mjs spelled 29 path literals — the page it maintains, the
four colliding isSystem declarations, the NON_READ_ANCHORS citations — and not one of
them is its population. isystem-census.mjs builds the census from
git ls-files packages examples, so a diff that merely SHIFTS a cited line reds the gate
in Lint & Repo Gates while the dispatch derivation places it in the silent bucket,
which reads as a clearance and is not.

Measured cost, from this card and its comments: three CI laps plus three repair dispatches
in one night, on three unrelated PRs, each after a dev had honestly run its derived
families and honestly reported green.

Premise re-check on fresh origin/main (a39b02a6b, clean tree) — HOLDS

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack \
--residue packages/metadata-protocol/src/protocol.ts
-> Silent (source names paths, none of which cover yours): 139 famil(ies)
- node scripts/check-system-context-census.mjs [lint.yml] names:
content/docs/permissions/system-context.mdx, packages/spec/src/kernel/execution-context.zod.ts, ...
(3 of 29 declared literals reach nothing tracked)
node scripts/check-system-context-census.mjs # exit captured before any pipe
-> EXIT 0: 109 elevation read sites in 20 packages across 45 files, all anchored;
145 anchors resolve, 27 declared non-read

Every number in the card re-derived unchanged (109 / 20 / 45 / 145). The Silent bucket is
139 today, not the 127 the card recorded — re-derived, not quoted.

Deliverable 1 — the Silent-bucket census, MEASURED

The engine seat's first-deliverable fence: classify the Silent families by "declared
population vs actually-read population". Static classification was tried first and was not
good enough (a recursive walk(dir) hides its seed root), so the population was
measured instead: every one of the 139 Silent families was run under an fs-tracing
preload that records the repo-relative path of every readFileSync / readdirSync /
git ls-files the gate makes, and the trace was compared against the literals
extractWatchHints reads out of that family's own sources.

Definition used, stated so the number is checkable: content reads only
(readFileSync/readFile/openSync/createReadStream) — statSync/existsSync probes
are excluded — of tracked files, minus the 5-path footprint pnpm itself reads.

bucketfamilies
read 20+ tracked files under packages/ or examples/ that no declared literal covers49
read 20+ undeclared tracked files anywhere53
read 1..19 undeclared files83
declaration covers every file read, or nothing tracked was read3
(of the 139, exited non-zero — trace is partial, so these UNDER-count)22

So this card is one member of a class, not a one-gate defect. The top of the list,
undeclared reads after declared literals:

familydeclaredundeclared reads
pnpm check:nul-bytes27815
node scripts/check-closing-keyword-parity.mjs67811
node scripts/check-self-test-workflow-commands.mjs76360
node scripts/check-position-name-fold-loaders.mjs76251
pnpm check:refd-timer-probe55661
node scripts/check-comment-mask-corpus.mjs15661
pnpm check:vendor-version-stamps25660
pnpm check:skill-identifier-liveness175495
pnpm check:parse-guard25449
pnpm check:engine-double-contract15410
node scripts/check-system-context-census.mjs295387
pnpm check:error-code-casing235161
node scripts/check-tenant-audit-census.mjs244177

⚠️ What the number is NOT: reads are an upper bound on the verdict-bearing population.
A gate that opens every package.json to build a workspace list reads far more than can
red it. Four were verified by reading the source — check:engine-double-contract
(SCAN_ROOTS = ['packages', 'examples'], one declared literal),
check:error-code-casing (SCAN_ROOTS = ['packages']), check:route-envelope
(walk(join(ROOT, 'packages'))), check:error-status-conformance (walk(SCAN_ROOT)) —
and all four are the same shape as this card. ⛔ The remaining members are NOT asserted to
each want this repair; three of the largest provably cannot take it (see below).

Already-worked subsets, so nothing here is re-filed:#13519 / PR #14188 repaired four
gates by declaring what they read; #14189 carries the three whole-tree gates
(check:nul-bytes, check-comment-mask-corpus, check:refd-timer-probe) for which a
truthful declaration is "every file" and is therefore refused by the derivation's own
"22 leads is the same as none" rule. The residue between those seven and the 49 measured
here is filed as a new finding (linked from this PR's card comment) — ⛔ not fixed here,
and its derivation-layer half queues behind #14013, which holds
scripts/pm/dispatch-gates.mjs right now.

Deliverable 2 — the family-bloat cost of the wide declaration, MEASURED FIRST

The services seat's fence: ⛔ do not adopt the wide declaration before measuring what it
costs an ordinary diff. Families derived per probe path, before -> after, at a39b02a6b:

probe pathbeforeafter
packages/lint/src/authoring-rules.ts1920
packages/plugins/plugin-auth/src/auth-plugin.ts2223
packages/metadata-protocol/src/protocol.ts2122
packages/spec/src/data/object.zod.ts4242 (already named — it is a declared literal)
examples/app-crm/package.json1718
content/docs/permissions/access-matrix.mdx3030
scripts/check-nul-bytes.mjs1414
.github/workflows/lint.yml2323

+1 family, and only on cards under the two declared subtrees. Nothing outside them
moves. The gate it adds runs in ~3s and CI runs it on every PR regardless, so the local
cost is one command against the CI lap it replaces. That is the measurement the services
seat asked for, and it is what carries the decision below.

The declaration shipped: WIDE

ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**'], the idiom
check-tenant-audit-census.mjs:146 already carries and check-watch-hint-literal already
gates. ⛔ No second pattern invented.

Narrow (the 20 packages / 45 files that carry a read site today) was considered and
refused on the gate's own terms: a roster of the files that carry a read site TODAY can
never name the file that grows one TOMORROW, and a NEW read site is exactly what check B
— the mandatory POPULATION half — exists to catch. A narrow declaration derives green for
the one case that most needs the lead, so it re-introduces this defect wearing the shape
of a fix. The services seat leaned the same way; the measurement above is what made it a
decision rather than a preference.

What holds the declaration honest

isystem-census.mjs now names its corpus roots once (CORPUS_ROOTS), collectCorpus
walks that constant, and the gate's --self-test derives both directions from it:
every walked root is declared, and no declared root is unwalked. A corpus root added or
dropped reds here instead of silently outrunning the declaration.

Reverse verification (both mutations on the committed tree, both legs restored)

Predicted direction: RED, plus the derivation dropping the gate.

MUTATION A the computed spelling ROOT_DIR_WATCH_HINTS = CORPUS_ROOTS.map(...)
on-disk proof: literal line 1 -> 0, computed line present, blob da3189a39 != HEAD 804912155
self-test EXIT 1 "declared exactly once, as an array of quoted literals"
check-watch-hint-literal EXIT 1 "the declaration is COMPUTED, not a literal array"
derivation for packages/lint/src/authoring-rules.ts 20 -> 19, census named: NO
MUTATION B drop one walked root ROOT_DIR_WATCH_HINTS = ['packages/**']
on-disk proof: new line present, old line absent, blob c44b2c2b4 != HEAD
self-test EXIT 1 "every root the census walks is declared"
restore (git checkout HEAD -- path, absolute, trap-guarded): git diff HEAD EMPTY and
hash-object == HEAD blob 804912155 after BOTH legs; post-restore self-test EXIT 0

Mutation A is the load-bearing one: identical runtime value, every runtime assertion still
green, and zero hints extracted — the measured proof that the literal spelling is what
carries this fix.

Checks run — union at 03edd9ce5 (the final commit of this branch)

Derived for the real changeset with node scripts/pm/dispatch-gates.mjs (no paths — the
script takes the change set off the merge base itself): 16 families, 14 by path + 2 by
change kind.

check:agent-test-spelling EXIT 0
check:bash32-floor EXIT 0
check:cli-command-ids EXIT 0
check:cross-package-test-inputs EXIT 0
check:entry-guard EXIT 0
check:parse-guard EXIT 0
check:pnpm-filter-targets EXIT 0
check:ratchet-remedy-authority EXIT 0 (named in the dispatch)
check:watch-hint-literal EXIT 0 43 declarations, ROOT_DIR_WATCH_HINTS 29
check:declared-population-live EXIT 0 156 of 200 families declare a live population
check:nul-bytes EXIT 0 7812 files scanned
check-ci-filter-parity.mjs EXIT 0
check-cross-package-test-inputs.mjs EXIT 0
check-shard-attestation.mjs EXIT 0
check-system-context-census.mjs EXIT 0 + --self-test EXIT 0 (all cases, 6 new)
check-tenant-audit-census.mjs EXIT 0 (cites this file at :77-84; those lines did not move)
bare-root-worklist.mjs --self-test EXIT 0 none stale, none missing, none contradicted
check-test-completeness.mjs NOT MEASURED — "PREREQUISITE NOT MET", exit 3: it grades a
saved turbo test log and no local log exists. Not a red.
check:pm-dispatch-gates EXIT 0 "dispatch-gates self-test: 1179 cases pass."

⚠️check:pm-dispatch-gates needed ~690s on this shared box (it builds temp git repos and
spawns child CLIs), which is past the container's ~10-minute foreground ceiling: two
foreground attempts were killed at 500s and at 520s under the shared verify lock, both with
no output at all. It was then run to completion and its exit code collected inside the same
turn. Recording that, because "killed at the ceiling" and "red" are not the same reading and
the first two attempts would have looked identical to a hang.

Exit codes were captured before any pipe (cmd > file 2>&1; EXIT=$?), and each line above
quotes the gate's own verdict line rather than a bare $?.

Changeset

skip-changeset: the diff is two CI-internal scripts under scripts/, publishes nothing
from any package, and releases nothing — the textbook case lint.yml names in its own
changeset-family comment. The label is applied on this PR.

Generated by Claude Code


Generated by Claude Code

…ually reads
The gate spelled 29 path literals -- the page it maintains and the spec seeds
it cites -- and none of them is its population. `isystem-census.mjs` builds the
census from `git ls-files packages examples`, so a diff that merely SHIFTS a
cited line reds the gate in CI while the dispatch derivation places it in the
`silent` bucket, which reads as a clearance and is not.
Declares `ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**']` using the idiom
`check-tenant-audit-census.mjs` already carries and `check-watch-hint-literal`
already gates, derives the corpus roots from a new `CORPUS_ROOTS` constant in
`isystem-census.mjs`, and pins both directions in the gate's own self-test so a
corpus root added or dropped cannot outrun the declaration.
Measured cost of the wide form: one extra derived family on cards under
`packages/**` / `examples/**` only, against a gate that runs in ~3s and that CI
runs on every PR regardless.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 2, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review September 2, 2026 03:10
@baozhoutao
baozhoutao added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 1f9175eSep 2, 2026
39 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14131-census-population-declaration branch September 2, 2026 03:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Declare the packages/examples census subtree check-system-context-census actually reads - #14323

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration
Sep 2, 2026
Merged

Declare the packages/examples census subtree check-system-context-census actually reads#14323
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration

Conversation

@baozhoutao

@baozhoutaobaozhoutao commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14131

check-system-context-census.mjs spelled 29 path literals — the page it maintains, the
four colliding isSystem declarations, the NON_READ_ANCHORS citations — and not one of
them is its population. isystem-census.mjs builds the census from
git ls-files packages examples, so a diff that merely SHIFTS a cited line reds the gate
in Lint & Repo Gates while the dispatch derivation places it in the silent bucket,
which reads as a clearance and is not.

Measured cost, from this card and its comments: three CI laps plus three repair dispatches
in one night, on three unrelated PRs, each after a dev had honestly run its derived
families and honestly reported green.

Premise re-check on fresh origin/main (a39b02a6b, clean tree) — HOLDS

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack \
--residue packages/metadata-protocol/src/protocol.ts
-> Silent (source names paths, none of which cover yours): 139 famil(ies)
- node scripts/check-system-context-census.mjs [lint.yml] names:
content/docs/permissions/system-context.mdx, packages/spec/src/kernel/execution-context.zod.ts, ...
(3 of 29 declared literals reach nothing tracked)
node scripts/check-system-context-census.mjs # exit captured before any pipe
-> EXIT 0: 109 elevation read sites in 20 packages across 45 files, all anchored;
145 anchors resolve, 27 declared non-read

Every number in the card re-derived unchanged (109 / 20 / 45 / 145). The Silent bucket is
139 today, not the 127 the card recorded — re-derived, not quoted.

Deliverable 1 — the Silent-bucket census, MEASURED

The engine seat's first-deliverable fence: classify the Silent families by "declared
population vs actually-read population". Static classification was tried first and was not
good enough (a recursive walk(dir) hides its seed root), so the population was
measured instead: every one of the 139 Silent families was run under an fs-tracing
preload that records the repo-relative path of every readFileSync / readdirSync /
git ls-files the gate makes, and the trace was compared against the literals
extractWatchHints reads out of that family's own sources.

Definition used, stated so the number is checkable: content reads only
(readFileSync/readFile/openSync/createReadStream) — statSync/existsSync probes
are excluded — of tracked files, minus the 5-path footprint pnpm itself reads.

bucketfamilies
read 20+ tracked files under packages/ or examples/ that no declared literal covers49
read 20+ undeclared tracked files anywhere53
read 1..19 undeclared files83
declaration covers every file read, or nothing tracked was read3
(of the 139, exited non-zero — trace is partial, so these UNDER-count)22

So this card is one member of a class, not a one-gate defect. The top of the list,
undeclared reads after declared literals:

familydeclaredundeclared reads
pnpm check:nul-bytes27815
node scripts/check-closing-keyword-parity.mjs67811
node scripts/check-self-test-workflow-commands.mjs76360
node scripts/check-position-name-fold-loaders.mjs76251
pnpm check:refd-timer-probe55661
node scripts/check-comment-mask-corpus.mjs15661
pnpm check:vendor-version-stamps25660
pnpm check:skill-identifier-liveness175495
pnpm check:parse-guard25449
pnpm check:engine-double-contract15410
node scripts/check-system-context-census.mjs295387
pnpm check:error-code-casing235161
node scripts/check-tenant-audit-census.mjs244177

⚠️ What the number is NOT: reads are an upper bound on the verdict-bearing population.
A gate that opens every package.json to build a workspace list reads far more than can
red it. Four were verified by reading the source — check:engine-double-contract
(SCAN_ROOTS = ['packages', 'examples'], one declared literal),
check:error-code-casing (SCAN_ROOTS = ['packages']), check:route-envelope
(walk(join(ROOT, 'packages'))), check:error-status-conformance (walk(SCAN_ROOT)) —
and all four are the same shape as this card. ⛔ The remaining members are NOT asserted to
each want this repair; three of the largest provably cannot take it (see below).

Already-worked subsets, so nothing here is re-filed:#13519 / PR #14188 repaired four
gates by declaring what they read; #14189 carries the three whole-tree gates
(check:nul-bytes, check-comment-mask-corpus, check:refd-timer-probe) for which a
truthful declaration is "every file" and is therefore refused by the derivation's own
"22 leads is the same as none" rule. The residue between those seven and the 49 measured
here is filed as a new finding (linked from this PR's card comment) — ⛔ not fixed here,
and its derivation-layer half queues behind #14013, which holds
scripts/pm/dispatch-gates.mjs right now.

Deliverable 2 — the family-bloat cost of the wide declaration, MEASURED FIRST

The services seat's fence: ⛔ do not adopt the wide declaration before measuring what it
costs an ordinary diff. Families derived per probe path, before -> after, at a39b02a6b:

probe pathbeforeafter
packages/lint/src/authoring-rules.ts1920
packages/plugins/plugin-auth/src/auth-plugin.ts2223
packages/metadata-protocol/src/protocol.ts2122
packages/spec/src/data/object.zod.ts4242 (already named — it is a declared literal)
examples/app-crm/package.json1718
content/docs/permissions/access-matrix.mdx3030
scripts/check-nul-bytes.mjs1414
.github/workflows/lint.yml2323

+1 family, and only on cards under the two declared subtrees. Nothing outside them
moves. The gate it adds runs in ~3s and CI runs it on every PR regardless, so the local
cost is one command against the CI lap it replaces. That is the measurement the services
seat asked for, and it is what carries the decision below.

The declaration shipped: WIDE

ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**'], the idiom
check-tenant-audit-census.mjs:146 already carries and check-watch-hint-literal already
gates. ⛔ No second pattern invented.

Narrow (the 20 packages / 45 files that carry a read site today) was considered and
refused on the gate's own terms: a roster of the files that carry a read site TODAY can
never name the file that grows one TOMORROW, and a NEW read site is exactly what check B
— the mandatory POPULATION half — exists to catch. A narrow declaration derives green for
the one case that most needs the lead, so it re-introduces this defect wearing the shape
of a fix. The services seat leaned the same way; the measurement above is what made it a
decision rather than a preference.

What holds the declaration honest

isystem-census.mjs now names its corpus roots once (CORPUS_ROOTS), collectCorpus
walks that constant, and the gate's --self-test derives both directions from it:
every walked root is declared, and no declared root is unwalked. A corpus root added or
dropped reds here instead of silently outrunning the declaration.

Reverse verification (both mutations on the committed tree, both legs restored)

Predicted direction: RED, plus the derivation dropping the gate.

MUTATION A the computed spelling ROOT_DIR_WATCH_HINTS = CORPUS_ROOTS.map(...)
on-disk proof: literal line 1 -> 0, computed line present, blob da3189a39 != HEAD 804912155
self-test EXIT 1 "declared exactly once, as an array of quoted literals"
check-watch-hint-literal EXIT 1 "the declaration is COMPUTED, not a literal array"
derivation for packages/lint/src/authoring-rules.ts 20 -> 19, census named: NO
MUTATION B drop one walked root ROOT_DIR_WATCH_HINTS = ['packages/**']
on-disk proof: new line present, old line absent, blob c44b2c2b4 != HEAD
self-test EXIT 1 "every root the census walks is declared"
restore (git checkout HEAD -- path, absolute, trap-guarded): git diff HEAD EMPTY and
hash-object == HEAD blob 804912155 after BOTH legs; post-restore self-test EXIT 0

Mutation A is the load-bearing one: identical runtime value, every runtime assertion still
green, and zero hints extracted — the measured proof that the literal spelling is what
carries this fix.

Checks run — union at 03edd9ce5 (the final commit of this branch)

Derived for the real changeset with node scripts/pm/dispatch-gates.mjs (no paths — the
script takes the change set off the merge base itself): 16 families, 14 by path + 2 by
change kind.

check:agent-test-spelling EXIT 0
check:bash32-floor EXIT 0
check:cli-command-ids EXIT 0
check:cross-package-test-inputs EXIT 0
check:entry-guard EXIT 0
check:parse-guard EXIT 0
check:pnpm-filter-targets EXIT 0
check:ratchet-remedy-authority EXIT 0 (named in the dispatch)
check:watch-hint-literal EXIT 0 43 declarations, ROOT_DIR_WATCH_HINTS 29
check:declared-population-live EXIT 0 156 of 200 families declare a live population
check:nul-bytes EXIT 0 7812 files scanned
check-ci-filter-parity.mjs EXIT 0
check-cross-package-test-inputs.mjs EXIT 0
check-shard-attestation.mjs EXIT 0
check-system-context-census.mjs EXIT 0 + --self-test EXIT 0 (all cases, 6 new)
check-tenant-audit-census.mjs EXIT 0 (cites this file at :77-84; those lines did not move)
bare-root-worklist.mjs --self-test EXIT 0 none stale, none missing, none contradicted
check-test-completeness.mjs NOT MEASURED — "PREREQUISITE NOT MET", exit 3: it grades a
saved turbo test log and no local log exists. Not a red.
check:pm-dispatch-gates EXIT 0 "dispatch-gates self-test: 1179 cases pass."

⚠️check:pm-dispatch-gates needed ~690s on this shared box (it builds temp git repos and
spawns child CLIs), which is past the container's ~10-minute foreground ceiling: two
foreground attempts were killed at 500s and at 520s under the shared verify lock, both with
no output at all. It was then run to completion and its exit code collected inside the same
turn. Recording that, because "killed at the ceiling" and "red" are not the same reading and
the first two attempts would have looked identical to a hang.

Exit codes were captured before any pipe (cmd > file 2>&1; EXIT=$?), and each line above
quotes the gate's own verdict line rather than a bare $?.

Changeset

skip-changeset: the diff is two CI-internal scripts under scripts/, publishes nothing
from any package, and releases nothing — the textbook case lint.yml names in its own
changeset-family comment. The label is applied on this PR.

Generated by Claude Code


Generated by Claude Code

…ually reads
The gate spelled 29 path literals -- the page it maintains and the spec seeds
it cites -- and none of them is its population. `isystem-census.mjs` builds the
census from `git ls-files packages examples`, so a diff that merely SHIFTS a
cited line reds the gate in CI while the dispatch derivation places it in the
`silent` bucket, which reads as a clearance and is not.
Declares `ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**']` using the idiom
`check-tenant-audit-census.mjs` already carries and `check-watch-hint-literal`
already gates, derives the corpus roots from a new `CORPUS_ROOTS` constant in
`isystem-census.mjs`, and pins both directions in the gate's own self-test so a
corpus root added or dropped cannot outrun the declaration.
Measured cost of the wide form: one extra derived family on cards under
`packages/**` / `examples/**` only, against a gate that runs in ~3s and that CI
runs on every PR regardless.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 2, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review September 2, 2026 03:10
@baozhoutao
baozhoutao added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 1f9175eSep 2, 2026
39 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14131-census-population-declaration branch September 2, 2026 03:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Declare the packages/examples census subtree check-system-context-census actually reads - #14323

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration
Sep 2, 2026
Merged

Declare the packages/examples census subtree check-system-context-census actually reads#14323
baozhoutao merged 1 commit into
mainfrom
claude/issue-14131-census-population-declaration

Conversation

@baozhoutao

@baozhoutaobaozhoutao commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14131

check-system-context-census.mjs spelled 29 path literals — the page it maintains, the
four colliding isSystem declarations, the NON_READ_ANCHORS citations — and not one of
them is its population. isystem-census.mjs builds the census from
git ls-files packages examples, so a diff that merely SHIFTS a cited line reds the gate
in Lint & Repo Gates while the dispatch derivation places it in the silent bucket,
which reads as a clearance and is not.

Measured cost, from this card and its comments: three CI laps plus three repair dispatches
in one night, on three unrelated PRs, each after a dev had honestly run its derived
families and honestly reported green.

Premise re-check on fresh origin/main (a39b02a6b, clean tree) — HOLDS

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack \
--residue packages/metadata-protocol/src/protocol.ts
-> Silent (source names paths, none of which cover yours): 139 famil(ies)
- node scripts/check-system-context-census.mjs [lint.yml] names:
content/docs/permissions/system-context.mdx, packages/spec/src/kernel/execution-context.zod.ts, ...
(3 of 29 declared literals reach nothing tracked)
node scripts/check-system-context-census.mjs # exit captured before any pipe
-> EXIT 0: 109 elevation read sites in 20 packages across 45 files, all anchored;
145 anchors resolve, 27 declared non-read

Every number in the card re-derived unchanged (109 / 20 / 45 / 145). The Silent bucket is
139 today, not the 127 the card recorded — re-derived, not quoted.

Deliverable 1 — the Silent-bucket census, MEASURED

The engine seat's first-deliverable fence: classify the Silent families by "declared
population vs actually-read population". Static classification was tried first and was not
good enough (a recursive walk(dir) hides its seed root), so the population was
measured instead: every one of the 139 Silent families was run under an fs-tracing
preload that records the repo-relative path of every readFileSync / readdirSync /
git ls-files the gate makes, and the trace was compared against the literals
extractWatchHints reads out of that family's own sources.

Definition used, stated so the number is checkable: content reads only
(readFileSync/readFile/openSync/createReadStream) — statSync/existsSync probes
are excluded — of tracked files, minus the 5-path footprint pnpm itself reads.

bucketfamilies
read 20+ tracked files under packages/ or examples/ that no declared literal covers49
read 20+ undeclared tracked files anywhere53
read 1..19 undeclared files83
declaration covers every file read, or nothing tracked was read3
(of the 139, exited non-zero — trace is partial, so these UNDER-count)22

So this card is one member of a class, not a one-gate defect. The top of the list,
undeclared reads after declared literals:

familydeclaredundeclared reads
pnpm check:nul-bytes27815
node scripts/check-closing-keyword-parity.mjs67811
node scripts/check-self-test-workflow-commands.mjs76360
node scripts/check-position-name-fold-loaders.mjs76251
pnpm check:refd-timer-probe55661
node scripts/check-comment-mask-corpus.mjs15661
pnpm check:vendor-version-stamps25660
pnpm check:skill-identifier-liveness175495
pnpm check:parse-guard25449
pnpm check:engine-double-contract15410
node scripts/check-system-context-census.mjs295387
pnpm check:error-code-casing235161
node scripts/check-tenant-audit-census.mjs244177

⚠️ What the number is NOT: reads are an upper bound on the verdict-bearing population.
A gate that opens every package.json to build a workspace list reads far more than can
red it. Four were verified by reading the source — check:engine-double-contract
(SCAN_ROOTS = ['packages', 'examples'], one declared literal),
check:error-code-casing (SCAN_ROOTS = ['packages']), check:route-envelope
(walk(join(ROOT, 'packages'))), check:error-status-conformance (walk(SCAN_ROOT)) —
and all four are the same shape as this card. ⛔ The remaining members are NOT asserted to
each want this repair; three of the largest provably cannot take it (see below).

Already-worked subsets, so nothing here is re-filed:#13519 / PR #14188 repaired four
gates by declaring what they read; #14189 carries the three whole-tree gates
(check:nul-bytes, check-comment-mask-corpus, check:refd-timer-probe) for which a
truthful declaration is "every file" and is therefore refused by the derivation's own
"22 leads is the same as none" rule. The residue between those seven and the 49 measured
here is filed as a new finding (linked from this PR's card comment) — ⛔ not fixed here,
and its derivation-layer half queues behind #14013, which holds
scripts/pm/dispatch-gates.mjs right now.

Deliverable 2 — the family-bloat cost of the wide declaration, MEASURED FIRST

The services seat's fence: ⛔ do not adopt the wide declaration before measuring what it
costs an ordinary diff. Families derived per probe path, before -> after, at a39b02a6b:

probe pathbeforeafter
packages/lint/src/authoring-rules.ts1920
packages/plugins/plugin-auth/src/auth-plugin.ts2223
packages/metadata-protocol/src/protocol.ts2122
packages/spec/src/data/object.zod.ts4242 (already named — it is a declared literal)
examples/app-crm/package.json1718
content/docs/permissions/access-matrix.mdx3030
scripts/check-nul-bytes.mjs1414
.github/workflows/lint.yml2323

+1 family, and only on cards under the two declared subtrees. Nothing outside them
moves. The gate it adds runs in ~3s and CI runs it on every PR regardless, so the local
cost is one command against the CI lap it replaces. That is the measurement the services
seat asked for, and it is what carries the decision below.

The declaration shipped: WIDE

ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**'], the idiom
check-tenant-audit-census.mjs:146 already carries and check-watch-hint-literal already
gates. ⛔ No second pattern invented.

Narrow (the 20 packages / 45 files that carry a read site today) was considered and
refused on the gate's own terms: a roster of the files that carry a read site TODAY can
never name the file that grows one TOMORROW, and a NEW read site is exactly what check B
— the mandatory POPULATION half — exists to catch. A narrow declaration derives green for
the one case that most needs the lead, so it re-introduces this defect wearing the shape
of a fix. The services seat leaned the same way; the measurement above is what made it a
decision rather than a preference.

What holds the declaration honest

isystem-census.mjs now names its corpus roots once (CORPUS_ROOTS), collectCorpus
walks that constant, and the gate's --self-test derives both directions from it:
every walked root is declared, and no declared root is unwalked. A corpus root added or
dropped reds here instead of silently outrunning the declaration.

Reverse verification (both mutations on the committed tree, both legs restored)

Predicted direction: RED, plus the derivation dropping the gate.

MUTATION A the computed spelling ROOT_DIR_WATCH_HINTS = CORPUS_ROOTS.map(...)
on-disk proof: literal line 1 -> 0, computed line present, blob da3189a39 != HEAD 804912155
self-test EXIT 1 "declared exactly once, as an array of quoted literals"
check-watch-hint-literal EXIT 1 "the declaration is COMPUTED, not a literal array"
derivation for packages/lint/src/authoring-rules.ts 20 -> 19, census named: NO
MUTATION B drop one walked root ROOT_DIR_WATCH_HINTS = ['packages/**']
on-disk proof: new line present, old line absent, blob c44b2c2b4 != HEAD
self-test EXIT 1 "every root the census walks is declared"
restore (git checkout HEAD -- path, absolute, trap-guarded): git diff HEAD EMPTY and
hash-object == HEAD blob 804912155 after BOTH legs; post-restore self-test EXIT 0

Mutation A is the load-bearing one: identical runtime value, every runtime assertion still
green, and zero hints extracted — the measured proof that the literal spelling is what
carries this fix.

Checks run — union at 03edd9ce5 (the final commit of this branch)

Derived for the real changeset with node scripts/pm/dispatch-gates.mjs (no paths — the
script takes the change set off the merge base itself): 16 families, 14 by path + 2 by
change kind.

check:agent-test-spelling EXIT 0
check:bash32-floor EXIT 0
check:cli-command-ids EXIT 0
check:cross-package-test-inputs EXIT 0
check:entry-guard EXIT 0
check:parse-guard EXIT 0
check:pnpm-filter-targets EXIT 0
check:ratchet-remedy-authority EXIT 0 (named in the dispatch)
check:watch-hint-literal EXIT 0 43 declarations, ROOT_DIR_WATCH_HINTS 29
check:declared-population-live EXIT 0 156 of 200 families declare a live population
check:nul-bytes EXIT 0 7812 files scanned
check-ci-filter-parity.mjs EXIT 0
check-cross-package-test-inputs.mjs EXIT 0
check-shard-attestation.mjs EXIT 0
check-system-context-census.mjs EXIT 0 + --self-test EXIT 0 (all cases, 6 new)
check-tenant-audit-census.mjs EXIT 0 (cites this file at :77-84; those lines did not move)
bare-root-worklist.mjs --self-test EXIT 0 none stale, none missing, none contradicted
check-test-completeness.mjs NOT MEASURED — "PREREQUISITE NOT MET", exit 3: it grades a
saved turbo test log and no local log exists. Not a red.
check:pm-dispatch-gates EXIT 0 "dispatch-gates self-test: 1179 cases pass."

⚠️check:pm-dispatch-gates needed ~690s on this shared box (it builds temp git repos and
spawns child CLIs), which is past the container's ~10-minute foreground ceiling: two
foreground attempts were killed at 500s and at 520s under the shared verify lock, both with
no output at all. It was then run to completion and its exit code collected inside the same
turn. Recording that, because "killed at the ceiling" and "red" are not the same reading and
the first two attempts would have looked identical to a hang.

Exit codes were captured before any pipe (cmd > file 2>&1; EXIT=$?), and each line above
quotes the gate's own verdict line rather than a bare $?.

Changeset

skip-changeset: the diff is two CI-internal scripts under scripts/, publishes nothing
from any package, and releases nothing — the textbook case lint.yml names in its own
changeset-family comment. The label is applied on this PR.

Generated by Claude Code


Generated by Claude Code

…ually reads
The gate spelled 29 path literals -- the page it maintains and the spec seeds
it cites -- and none of them is its population. `isystem-census.mjs` builds the
census from `git ls-files packages examples`, so a diff that merely SHIFTS a
cited line reds the gate in CI while the dispatch derivation places it in the
`silent` bucket, which reads as a clearance and is not.
Declares `ROOT_DIR_WATCH_HINTS = ['packages/**', 'examples/**']` using the idiom
`check-tenant-audit-census.mjs` already carries and `check-watch-hint-literal`
already gates, derives the corpus roots from a new `CORPUS_ROOTS` constant in
`isystem-census.mjs`, and pins both directions in the gate's own self-test so a
corpus root added or dropped cannot outrun the declaration.
Measured cost of the wide form: one extra derived family on cards under
`packages/**` / `examples/**` only, against a gate that runs in ~3s and that CI
runs on every PR regardless.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 2, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review September 2, 2026 03:10
@baozhoutao
baozhoutao added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit 1f9175eSep 2, 2026
39 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14131-census-population-declaration branch September 2, 2026 03:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@baozhoutao@claude