Declare the scripts/ population two Silent gate families walk but never named - #14692

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1
Sep 2, 2026
Merged

Declare the scripts/ population two Silent gate families walk but never named#14692
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Part of #14325 — sitting 1 of the per-gate half. The card stays open: the residue is not exhausted, and this sitting's measurement changes what the rest of it is.

What landed

Two gate families now declare the scripts/ population they walk but never named, in their own module body under the ROOT_DIR_WATCH_HINTS idiom, each pinned in its own --self-test — the shape PR #14188 and PR #14323 landed.

familydeclaredwhy it was silentresidue before ⇢ afterself-test pin
node scripts/check-self-test-wired.mjsscripts/**/*.mjs, scripts/**/*.mts, scripts/**/*.shcorpus root arrives as join(ROOT, 'scripts') — a bare single-segment word the extractor cannot see; its only other literals are the six scripts its ledger cites BY NAME (an artifact roster)Silent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.tsbattery population declaration, 7 cases, floor pinned
node scripts/check-whole-set-label-write.mjsscripts/**/*.mjs, scripts/**/*.ts, scripts/**/*.shtwo of three ROOTS carry a separator and were recovered; the third is the bare word scripts. The rest of its literals are two owner/repo action slugs and fixture sandbox filenamesSilent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.ts8 POPULATION cases in selfTest()

Measured with the derivation's own --residue, probe scripts/check-nul-bytes.mjs: 14 matched families ⇢ 16, Silent 148 ⇢ 146. With an outside probe the verdict is unchanged, so neither declaration over-claims.

One hint per admitted extension, not the bare subtree.check-ratchet-remedy-authority.mjs sets that precedent at this same root and its own self-test refuses the subtree spelling. scripts/** would name both gates for the 91 JSON, Markdown and text files under the root that neither one opens. The declared set is SET-EQUAL to each gate's live walk — 221 of 312 and 219 of 312 tracked files, nothing walked left uncovered, nothing covered left unwalked. An extension the filter admits but the tree does not yet HOLD (.js, .cjs, .yml, .yaml) is deliberately absent: a hint reaching nothing tracked is a dead lead the consumer reports as a population. The pins redden the day such a file lands.

⚠️ The finding this sitting is really for: the residue head is NOT a hint-line backlog

The card's own warning — reads are an upper bound — turns out to be the whole story, and the number is now measured rather than suspected.

Census re-derived on this branch's base (2aa8456cf), method as the card specifies: --residue for the Silent bucket, then every enumerating candidate run under an fs-tracing preload, compared against the literals extractWatchHints recovers from its own sources and judged with the derivation's own hintCovers. 202 families discovered, 132 Silent and non-self-test, 82 of those enumerate a directory, 49 read 5 or more undeclared tracked files.

Of those 49:

bucketndisposition
whole-tree6out of scope, #14189's channel — includes the three this census re-confirms (check-closing-keyword-parity, check-self-test-workflow-commands, check:watch-hint-literal)
declared this sitting2the only members with a NARROW, high-precision, undeclared population
root-wide, ledger already REFUSED13scripts/pm/bare-root-worklist.mjs records a verdict for each
root-wide, same class, no ledger row1432–52% of a 5837-file root — the identical trade, unrecorded
low precision (under 10%)14incidental or artifact reads; no honest subtree to declare

The head of the residue is the REFUSE-WIDE class, and this repo has already adjudicated it.scripts/pm/bare-root-worklist.mjs is a maintained, self-tested ledger of exactly this species and reports 0 untriaged rows. Every one of the four members the card source-confirmed as the natural head of sitting 1 is either recorded there as refused, or is unrecorded but measures into the same class:

  • check:engine-double-contract — REFUSE-WIDE on both roots (measured 90% / 84%), with the split refused by name
  • check:error-code-casing — REFUSE-WIDE, "same trade as engine-double-contract"
  • check:error-status-conformance — REFUSE-WIDE at 39%
  • check:route-envelopeno ledger row; walks join(ROOT, 'packages') over non-test .ts, measured here at 2138 undeclared reads = 36.6% of the root. Same class as check:authz-resolver, which IS recorded REFUSE-WIDE at 39%.

The ledger states the trade in its own words: a bare-root declaration there "would be TRUE, and is refused anyway: it names the gate for every card under a root the fleet already declares wholesale, so the matched column stops discriminating and restates 'run the farm', which CI does regardless." It also records the maintainer ruling of 2026-08-26 that split the spellable-but-undeclared rows by measured downstream pull — rows with a recorded consumer get the declaration, rows without stay deferred.

Sitting 2 cannot be "the next 8 by read count". Continuing down this order means declaring packages/** on gates whose recorded verdict refuses exactly that, which is a re-decision of a maintainer-ruled map, not the mechanical repair this card scoped. Three honest routes, for triage rather than for a dev to pick:

  1. Stop the per-gate half here. The narrow-subtree population the card describes was real and is now exhausted at two members; the rest of the residue is the width trade, already priced.
  2. Per-member consumer evidence. Take the 14 unrecorded root-wide members one at a time, and declare only where a MEASURED consumer exists (a card that ran a green local union and lost a CI round to that gate) — the criterion the 2026-08-26 ruling already uses. That is a p2-per-member shape, as the triage says.
  3. Record the 14 unrecorded members in the ledger so the class is closed by evidence rather than left looking like outstanding debt. This is a bare-root-worklist.mjs edit, so it belongs to a card that owns that file.

⛔ None of these is taken here. scripts/pm/dispatch-gates.mjs is untouched, as scoped.

Artifact-only by design, recorded rather than declared

check-self-test-wired and check-whole-set-label-write each ALSO name individual files — the ledger rows one cites, the action slugs and probe paths the other pins. Those stay as they are: they are artifacts the gate names, not a population it reads, and the new declaration sits beside them rather than replacing them. The 14 low-precision members above are the same shape at family scale and are recorded here, not declared.

Verification

Union derived in this worktree by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths passed — the script takes its own changeset), 17 commands, re-derived unchanged after merging origin/main. Run at be6800e2f:

  • 16 of 17 green, including check:watch-hint-literal (47 declarations across 4 rostered names), check:ratchet-remedy-authority, check:pm-dispatch-gates (VERDICT command-exit 0, dispatch-gates self-test 1240 cases pass), and node scripts/pm/bare-root-worklist.mjs --self-test ("none stale, none missing, none contradicted" — the new declarations create no fresh untriaged row and contradict no recorded verdict)
  • node scripts/check-declared-population-live.mjs — "158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8006 tracked file(s)"
  • both gates' production leg and --self-test leg green; check-self-test-wired prints "scope: 221 file(s) under scripts/", which is the declared set exactly
  • node scripts/check-test-completeness.mjs exits 3 = NOT MEASURED by its own design — it needs a CI test log and says so in its own output. Not a red.

Ablation — the pins are proved able to go red. Five legs, each mutating the committed declaration, each proved on disk by counting the removed and injected text before reading any result, each restored via git checkout HEAD and verified by git hash-object against the HEAD blob (both MATCH):

legexpectedobserved
drop scripts/**/*.shREDexit 1 — "a file this gate WALKS is left undeclared"
add scripts/**/*.jsonREDexit 1 — "a declared hint reaches nothing this gate walks — a dead lead"
rewrite as a computed .map() spellingREDexit 1 — "the declaration is not a single literal array of quoted strings"
drop scripts/**/*.tsREDexit 1 — "every file this gate walks under scripts/ is declared: expected true, got false"
replace with the bare scripts/**REDexit 1 — 4 failures, including the extension and dead-lead pins

⚠️ Reported rather than hidden: the FIRST ablation harness was a no-op — its perl replacer failed to compile on the glob metacharacters and changed nothing. The on-disk proof step caught it and the readings were voided; the table above is the re-run with an exact-literal replacer. Had that step been skipped, five green self-tests would have read as five passing ablations.

git diff --stat against the base: 2 files changed, 212 insertions(+), 1 deletion(-) — both under scripts/, so skip-changeset.

Serial check: every open PR's file list was read before editing; neither gate file is held. scripts/check-skills-token-ratchet.mjs (3 open PRs) and scripts/check-type-check-coverage.mjs (1) are held and were excluded from this sitting on that ground as well as on precision.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV


Generated by Claude Code

`scripts/pm/dispatch-gates.mjs` builds every dispatch's gate list by scanning a
gate's own source for the path literals it operates on, and "looks like a path"
there means "carries a separator". Both gates below seed a recursive walk at the
bare single-segment word `scripts`, which the extractor cannot see at all, so the
only literals recoverable from either file named individual artifacts: the six
scripts one gate's ledger cites by name, and two `owner/repo` action slugs plus
sandbox filenames in the other. An artifact roster is not a population -- a list
of the files that already exist can never contain the one added tomorrow -- so
both families walked all of `scripts/` and appeared on no card that edited any
of it.
Each now declares that population in its own module body under the
ROOT_DIR_WATCH_HINTS idiom, pinned in its own --self-test against the LIVE walk
in both directions: nothing walked left uncovered, nothing covered left unwalked.
One hint per admitted extension rather than the bare subtree, following
check-ratchet-remedy-authority.mjs at this same root -- `scripts/**` would name
both gates for the 91 JSON, Markdown and text files under the root that neither
one opens. An extension the filter admits but the tree does not yet hold is
deliberately absent, because a hint reaching nothing tracked is a dead lead the
consumer reports as a population; the pins redden the day such a file lands.
Measured on this tree with the derivation's own --residue, probe
scripts/check-nul-bytes.mjs: 14 matched families -> 16, Silent 148 -> 146. With
an outside probe (packages/metadata-protocol/src/protocol.ts) both stay Silent,
so the declaration does not over-claim.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33678836122 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: expected 'SIGKILL' to be null
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 20 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Merged via the queue into main with commit e5d530eSep 2, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14325-silent-gate-declarations-s1 branch September 2, 2026 20:52
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
…the sandbox-filename fix
12 of #14695's 14 unrecorded REFUSE-WIDE members are recorded in a new
CENSUS_REFUSE_WIDE table in scripts/pm/bare-root-worklist.mjs, each with its
own measured share and the base commit (2aa8456, the base #14325's own
census used) it was measured at. A new table rather than new TRIAGE rows:
TRIAGE is coupled to sweep(), which can only discover a bare-word population
literal assigned to a POPULATION_CONSTANT-shaped name, and none of these
families hold that shape (confirmed empirically: adding one to TRIAGE makes
--self-test fail STALE immediately). Two of the fourteen ("the two
packages/spec-filtered ones") are not recorded -- PR #14692's body, read in
full, does not name them, and guessing would fabricate a measurement no one
took.
Also folds in the small second half: scripts/check-whole-set-label-write.mjs's
three self-test sandbox filenames (scripts/w.mjs, scripts/writer.sh,
.github/workflows/w.yml) existed in no tracked tree and, spelled as bare
literals in a top-level export outside any selfTest()-shaped function, entered
the gate's own declared-population hint set as dead leads. Renamed to three
real, unrelated, already-tracked paths; no behaviour change to the gate's
verdict.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
… 14)
Follow-up to a36af67, which shipped 12 of 14 and left the two
`packages/spec`-filtered members ("check:error-code-provenance",
"check:objectui-pin-citations") as an open question -- the issue text's
claim that they were named in PR #14692's body with their shares did not
hold up against that body's actual text.
The filing session's own sitting-1 census artifacts supplied the two names
(both in its "root-wide, same class, no ledger row" bucket, members 13 and
14). Re-measured here by this table's own method rather than copied: strace
openat tracing against a 2aa8456 worktree, run via
`pnpm --filter @objectstack/spec run check:X` (tsx production leg). Both
land within 1 file of the filing session's own sitting-1 counts
(2070 vs 2069, and an exact 1192 vs 1192) -- corroborating the method a
second time, now on a tsx-run gate rather than a plain node one.
check:objectui-pin-citations (20.4%) lands below the issue's summarised
32-52% band; recorded as measured rather than forced into it.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
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

Development

Successfully merging this pull request may close these issues.

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 scripts/ population two Silent gate families walk but never named - #14692

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1
Sep 2, 2026
Merged

Declare the scripts/ population two Silent gate families walk but never named#14692
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Part of #14325 — sitting 1 of the per-gate half. The card stays open: the residue is not exhausted, and this sitting's measurement changes what the rest of it is.

What landed

Two gate families now declare the scripts/ population they walk but never named, in their own module body under the ROOT_DIR_WATCH_HINTS idiom, each pinned in its own --self-test — the shape PR #14188 and PR #14323 landed.

familydeclaredwhy it was silentresidue before ⇢ afterself-test pin
node scripts/check-self-test-wired.mjsscripts/**/*.mjs, scripts/**/*.mts, scripts/**/*.shcorpus root arrives as join(ROOT, 'scripts') — a bare single-segment word the extractor cannot see; its only other literals are the six scripts its ledger cites BY NAME (an artifact roster)Silent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.tsbattery population declaration, 7 cases, floor pinned
node scripts/check-whole-set-label-write.mjsscripts/**/*.mjs, scripts/**/*.ts, scripts/**/*.shtwo of three ROOTS carry a separator and were recovered; the third is the bare word scripts. The rest of its literals are two owner/repo action slugs and fixture sandbox filenamesSilent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.ts8 POPULATION cases in selfTest()

Measured with the derivation's own --residue, probe scripts/check-nul-bytes.mjs: 14 matched families ⇢ 16, Silent 148 ⇢ 146. With an outside probe the verdict is unchanged, so neither declaration over-claims.

One hint per admitted extension, not the bare subtree.check-ratchet-remedy-authority.mjs sets that precedent at this same root and its own self-test refuses the subtree spelling. scripts/** would name both gates for the 91 JSON, Markdown and text files under the root that neither one opens. The declared set is SET-EQUAL to each gate's live walk — 221 of 312 and 219 of 312 tracked files, nothing walked left uncovered, nothing covered left unwalked. An extension the filter admits but the tree does not yet HOLD (.js, .cjs, .yml, .yaml) is deliberately absent: a hint reaching nothing tracked is a dead lead the consumer reports as a population. The pins redden the day such a file lands.

⚠️ The finding this sitting is really for: the residue head is NOT a hint-line backlog

The card's own warning — reads are an upper bound — turns out to be the whole story, and the number is now measured rather than suspected.

Census re-derived on this branch's base (2aa8456cf), method as the card specifies: --residue for the Silent bucket, then every enumerating candidate run under an fs-tracing preload, compared against the literals extractWatchHints recovers from its own sources and judged with the derivation's own hintCovers. 202 families discovered, 132 Silent and non-self-test, 82 of those enumerate a directory, 49 read 5 or more undeclared tracked files.

Of those 49:

bucketndisposition
whole-tree6out of scope, #14189's channel — includes the three this census re-confirms (check-closing-keyword-parity, check-self-test-workflow-commands, check:watch-hint-literal)
declared this sitting2the only members with a NARROW, high-precision, undeclared population
root-wide, ledger already REFUSED13scripts/pm/bare-root-worklist.mjs records a verdict for each
root-wide, same class, no ledger row1432–52% of a 5837-file root — the identical trade, unrecorded
low precision (under 10%)14incidental or artifact reads; no honest subtree to declare

The head of the residue is the REFUSE-WIDE class, and this repo has already adjudicated it.scripts/pm/bare-root-worklist.mjs is a maintained, self-tested ledger of exactly this species and reports 0 untriaged rows. Every one of the four members the card source-confirmed as the natural head of sitting 1 is either recorded there as refused, or is unrecorded but measures into the same class:

  • check:engine-double-contract — REFUSE-WIDE on both roots (measured 90% / 84%), with the split refused by name
  • check:error-code-casing — REFUSE-WIDE, "same trade as engine-double-contract"
  • check:error-status-conformance — REFUSE-WIDE at 39%
  • check:route-envelopeno ledger row; walks join(ROOT, 'packages') over non-test .ts, measured here at 2138 undeclared reads = 36.6% of the root. Same class as check:authz-resolver, which IS recorded REFUSE-WIDE at 39%.

The ledger states the trade in its own words: a bare-root declaration there "would be TRUE, and is refused anyway: it names the gate for every card under a root the fleet already declares wholesale, so the matched column stops discriminating and restates 'run the farm', which CI does regardless." It also records the maintainer ruling of 2026-08-26 that split the spellable-but-undeclared rows by measured downstream pull — rows with a recorded consumer get the declaration, rows without stay deferred.

Sitting 2 cannot be "the next 8 by read count". Continuing down this order means declaring packages/** on gates whose recorded verdict refuses exactly that, which is a re-decision of a maintainer-ruled map, not the mechanical repair this card scoped. Three honest routes, for triage rather than for a dev to pick:

  1. Stop the per-gate half here. The narrow-subtree population the card describes was real and is now exhausted at two members; the rest of the residue is the width trade, already priced.
  2. Per-member consumer evidence. Take the 14 unrecorded root-wide members one at a time, and declare only where a MEASURED consumer exists (a card that ran a green local union and lost a CI round to that gate) — the criterion the 2026-08-26 ruling already uses. That is a p2-per-member shape, as the triage says.
  3. Record the 14 unrecorded members in the ledger so the class is closed by evidence rather than left looking like outstanding debt. This is a bare-root-worklist.mjs edit, so it belongs to a card that owns that file.

⛔ None of these is taken here. scripts/pm/dispatch-gates.mjs is untouched, as scoped.

Artifact-only by design, recorded rather than declared

check-self-test-wired and check-whole-set-label-write each ALSO name individual files — the ledger rows one cites, the action slugs and probe paths the other pins. Those stay as they are: they are artifacts the gate names, not a population it reads, and the new declaration sits beside them rather than replacing them. The 14 low-precision members above are the same shape at family scale and are recorded here, not declared.

Verification

Union derived in this worktree by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths passed — the script takes its own changeset), 17 commands, re-derived unchanged after merging origin/main. Run at be6800e2f:

  • 16 of 17 green, including check:watch-hint-literal (47 declarations across 4 rostered names), check:ratchet-remedy-authority, check:pm-dispatch-gates (VERDICT command-exit 0, dispatch-gates self-test 1240 cases pass), and node scripts/pm/bare-root-worklist.mjs --self-test ("none stale, none missing, none contradicted" — the new declarations create no fresh untriaged row and contradict no recorded verdict)
  • node scripts/check-declared-population-live.mjs — "158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8006 tracked file(s)"
  • both gates' production leg and --self-test leg green; check-self-test-wired prints "scope: 221 file(s) under scripts/", which is the declared set exactly
  • node scripts/check-test-completeness.mjs exits 3 = NOT MEASURED by its own design — it needs a CI test log and says so in its own output. Not a red.

Ablation — the pins are proved able to go red. Five legs, each mutating the committed declaration, each proved on disk by counting the removed and injected text before reading any result, each restored via git checkout HEAD and verified by git hash-object against the HEAD blob (both MATCH):

legexpectedobserved
drop scripts/**/*.shREDexit 1 — "a file this gate WALKS is left undeclared"
add scripts/**/*.jsonREDexit 1 — "a declared hint reaches nothing this gate walks — a dead lead"
rewrite as a computed .map() spellingREDexit 1 — "the declaration is not a single literal array of quoted strings"
drop scripts/**/*.tsREDexit 1 — "every file this gate walks under scripts/ is declared: expected true, got false"
replace with the bare scripts/**REDexit 1 — 4 failures, including the extension and dead-lead pins

⚠️ Reported rather than hidden: the FIRST ablation harness was a no-op — its perl replacer failed to compile on the glob metacharacters and changed nothing. The on-disk proof step caught it and the readings were voided; the table above is the re-run with an exact-literal replacer. Had that step been skipped, five green self-tests would have read as five passing ablations.

git diff --stat against the base: 2 files changed, 212 insertions(+), 1 deletion(-) — both under scripts/, so skip-changeset.

Serial check: every open PR's file list was read before editing; neither gate file is held. scripts/check-skills-token-ratchet.mjs (3 open PRs) and scripts/check-type-check-coverage.mjs (1) are held and were excluded from this sitting on that ground as well as on precision.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV


Generated by Claude Code

`scripts/pm/dispatch-gates.mjs` builds every dispatch's gate list by scanning a
gate's own source for the path literals it operates on, and "looks like a path"
there means "carries a separator". Both gates below seed a recursive walk at the
bare single-segment word `scripts`, which the extractor cannot see at all, so the
only literals recoverable from either file named individual artifacts: the six
scripts one gate's ledger cites by name, and two `owner/repo` action slugs plus
sandbox filenames in the other. An artifact roster is not a population -- a list
of the files that already exist can never contain the one added tomorrow -- so
both families walked all of `scripts/` and appeared on no card that edited any
of it.
Each now declares that population in its own module body under the
ROOT_DIR_WATCH_HINTS idiom, pinned in its own --self-test against the LIVE walk
in both directions: nothing walked left uncovered, nothing covered left unwalked.
One hint per admitted extension rather than the bare subtree, following
check-ratchet-remedy-authority.mjs at this same root -- `scripts/**` would name
both gates for the 91 JSON, Markdown and text files under the root that neither
one opens. An extension the filter admits but the tree does not yet hold is
deliberately absent, because a hint reaching nothing tracked is a dead lead the
consumer reports as a population; the pins redden the day such a file lands.
Measured on this tree with the derivation's own --residue, probe
scripts/check-nul-bytes.mjs: 14 matched families -> 16, Silent 148 -> 146. With
an outside probe (packages/metadata-protocol/src/protocol.ts) both stay Silent,
so the declaration does not over-claim.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33678836122 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: expected 'SIGKILL' to be null
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 20 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Merged via the queue into main with commit e5d530eSep 2, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14325-silent-gate-declarations-s1 branch September 2, 2026 20:52
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
…the sandbox-filename fix
12 of #14695's 14 unrecorded REFUSE-WIDE members are recorded in a new
CENSUS_REFUSE_WIDE table in scripts/pm/bare-root-worklist.mjs, each with its
own measured share and the base commit (2aa8456, the base #14325's own
census used) it was measured at. A new table rather than new TRIAGE rows:
TRIAGE is coupled to sweep(), which can only discover a bare-word population
literal assigned to a POPULATION_CONSTANT-shaped name, and none of these
families hold that shape (confirmed empirically: adding one to TRIAGE makes
--self-test fail STALE immediately). Two of the fourteen ("the two
packages/spec-filtered ones") are not recorded -- PR #14692's body, read in
full, does not name them, and guessing would fabricate a measurement no one
took.
Also folds in the small second half: scripts/check-whole-set-label-write.mjs's
three self-test sandbox filenames (scripts/w.mjs, scripts/writer.sh,
.github/workflows/w.yml) existed in no tracked tree and, spelled as bare
literals in a top-level export outside any selfTest()-shaped function, entered
the gate's own declared-population hint set as dead leads. Renamed to three
real, unrelated, already-tracked paths; no behaviour change to the gate's
verdict.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
… 14)
Follow-up to a36af67, which shipped 12 of 14 and left the two
`packages/spec`-filtered members ("check:error-code-provenance",
"check:objectui-pin-citations") as an open question -- the issue text's
claim that they were named in PR #14692's body with their shares did not
hold up against that body's actual text.
The filing session's own sitting-1 census artifacts supplied the two names
(both in its "root-wide, same class, no ledger row" bucket, members 13 and
14). Re-measured here by this table's own method rather than copied: strace
openat tracing against a 2aa8456 worktree, run via
`pnpm --filter @objectstack/spec run check:X` (tsx production leg). Both
land within 1 file of the filing session's own sitting-1 counts
(2070 vs 2069, and an exact 1192 vs 1192) -- corroborating the method a
second time, now on a tsx-run gate rather than a plain node one.
check:objectui-pin-citations (20.4%) lands below the issue's summarised
32-52% band; recorded as measured rather than forced into it.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
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

Development

Successfully merging this pull request may close these issues.

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 scripts/ population two Silent gate families walk but never named - #14692

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1
Sep 2, 2026
Merged

Declare the scripts/ population two Silent gate families walk but never named#14692
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Part of #14325 — sitting 1 of the per-gate half. The card stays open: the residue is not exhausted, and this sitting's measurement changes what the rest of it is.

What landed

Two gate families now declare the scripts/ population they walk but never named, in their own module body under the ROOT_DIR_WATCH_HINTS idiom, each pinned in its own --self-test — the shape PR #14188 and PR #14323 landed.

familydeclaredwhy it was silentresidue before ⇢ afterself-test pin
node scripts/check-self-test-wired.mjsscripts/**/*.mjs, scripts/**/*.mts, scripts/**/*.shcorpus root arrives as join(ROOT, 'scripts') — a bare single-segment word the extractor cannot see; its only other literals are the six scripts its ledger cites BY NAME (an artifact roster)Silent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.tsbattery population declaration, 7 cases, floor pinned
node scripts/check-whole-set-label-write.mjsscripts/**/*.mjs, scripts/**/*.ts, scripts/**/*.shtwo of three ROOTS carry a separator and were recovered; the third is the bare word scripts. The rest of its literals are two owner/repo action slugs and fixture sandbox filenamesSilent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.ts8 POPULATION cases in selfTest()

Measured with the derivation's own --residue, probe scripts/check-nul-bytes.mjs: 14 matched families ⇢ 16, Silent 148 ⇢ 146. With an outside probe the verdict is unchanged, so neither declaration over-claims.

One hint per admitted extension, not the bare subtree.check-ratchet-remedy-authority.mjs sets that precedent at this same root and its own self-test refuses the subtree spelling. scripts/** would name both gates for the 91 JSON, Markdown and text files under the root that neither one opens. The declared set is SET-EQUAL to each gate's live walk — 221 of 312 and 219 of 312 tracked files, nothing walked left uncovered, nothing covered left unwalked. An extension the filter admits but the tree does not yet HOLD (.js, .cjs, .yml, .yaml) is deliberately absent: a hint reaching nothing tracked is a dead lead the consumer reports as a population. The pins redden the day such a file lands.

⚠️ The finding this sitting is really for: the residue head is NOT a hint-line backlog

The card's own warning — reads are an upper bound — turns out to be the whole story, and the number is now measured rather than suspected.

Census re-derived on this branch's base (2aa8456cf), method as the card specifies: --residue for the Silent bucket, then every enumerating candidate run under an fs-tracing preload, compared against the literals extractWatchHints recovers from its own sources and judged with the derivation's own hintCovers. 202 families discovered, 132 Silent and non-self-test, 82 of those enumerate a directory, 49 read 5 or more undeclared tracked files.

Of those 49:

bucketndisposition
whole-tree6out of scope, #14189's channel — includes the three this census re-confirms (check-closing-keyword-parity, check-self-test-workflow-commands, check:watch-hint-literal)
declared this sitting2the only members with a NARROW, high-precision, undeclared population
root-wide, ledger already REFUSED13scripts/pm/bare-root-worklist.mjs records a verdict for each
root-wide, same class, no ledger row1432–52% of a 5837-file root — the identical trade, unrecorded
low precision (under 10%)14incidental or artifact reads; no honest subtree to declare

The head of the residue is the REFUSE-WIDE class, and this repo has already adjudicated it.scripts/pm/bare-root-worklist.mjs is a maintained, self-tested ledger of exactly this species and reports 0 untriaged rows. Every one of the four members the card source-confirmed as the natural head of sitting 1 is either recorded there as refused, or is unrecorded but measures into the same class:

  • check:engine-double-contract — REFUSE-WIDE on both roots (measured 90% / 84%), with the split refused by name
  • check:error-code-casing — REFUSE-WIDE, "same trade as engine-double-contract"
  • check:error-status-conformance — REFUSE-WIDE at 39%
  • check:route-envelopeno ledger row; walks join(ROOT, 'packages') over non-test .ts, measured here at 2138 undeclared reads = 36.6% of the root. Same class as check:authz-resolver, which IS recorded REFUSE-WIDE at 39%.

The ledger states the trade in its own words: a bare-root declaration there "would be TRUE, and is refused anyway: it names the gate for every card under a root the fleet already declares wholesale, so the matched column stops discriminating and restates 'run the farm', which CI does regardless." It also records the maintainer ruling of 2026-08-26 that split the spellable-but-undeclared rows by measured downstream pull — rows with a recorded consumer get the declaration, rows without stay deferred.

Sitting 2 cannot be "the next 8 by read count". Continuing down this order means declaring packages/** on gates whose recorded verdict refuses exactly that, which is a re-decision of a maintainer-ruled map, not the mechanical repair this card scoped. Three honest routes, for triage rather than for a dev to pick:

  1. Stop the per-gate half here. The narrow-subtree population the card describes was real and is now exhausted at two members; the rest of the residue is the width trade, already priced.
  2. Per-member consumer evidence. Take the 14 unrecorded root-wide members one at a time, and declare only where a MEASURED consumer exists (a card that ran a green local union and lost a CI round to that gate) — the criterion the 2026-08-26 ruling already uses. That is a p2-per-member shape, as the triage says.
  3. Record the 14 unrecorded members in the ledger so the class is closed by evidence rather than left looking like outstanding debt. This is a bare-root-worklist.mjs edit, so it belongs to a card that owns that file.

⛔ None of these is taken here. scripts/pm/dispatch-gates.mjs is untouched, as scoped.

Artifact-only by design, recorded rather than declared

check-self-test-wired and check-whole-set-label-write each ALSO name individual files — the ledger rows one cites, the action slugs and probe paths the other pins. Those stay as they are: they are artifacts the gate names, not a population it reads, and the new declaration sits beside them rather than replacing them. The 14 low-precision members above are the same shape at family scale and are recorded here, not declared.

Verification

Union derived in this worktree by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths passed — the script takes its own changeset), 17 commands, re-derived unchanged after merging origin/main. Run at be6800e2f:

  • 16 of 17 green, including check:watch-hint-literal (47 declarations across 4 rostered names), check:ratchet-remedy-authority, check:pm-dispatch-gates (VERDICT command-exit 0, dispatch-gates self-test 1240 cases pass), and node scripts/pm/bare-root-worklist.mjs --self-test ("none stale, none missing, none contradicted" — the new declarations create no fresh untriaged row and contradict no recorded verdict)
  • node scripts/check-declared-population-live.mjs — "158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8006 tracked file(s)"
  • both gates' production leg and --self-test leg green; check-self-test-wired prints "scope: 221 file(s) under scripts/", which is the declared set exactly
  • node scripts/check-test-completeness.mjs exits 3 = NOT MEASURED by its own design — it needs a CI test log and says so in its own output. Not a red.

Ablation — the pins are proved able to go red. Five legs, each mutating the committed declaration, each proved on disk by counting the removed and injected text before reading any result, each restored via git checkout HEAD and verified by git hash-object against the HEAD blob (both MATCH):

legexpectedobserved
drop scripts/**/*.shREDexit 1 — "a file this gate WALKS is left undeclared"
add scripts/**/*.jsonREDexit 1 — "a declared hint reaches nothing this gate walks — a dead lead"
rewrite as a computed .map() spellingREDexit 1 — "the declaration is not a single literal array of quoted strings"
drop scripts/**/*.tsREDexit 1 — "every file this gate walks under scripts/ is declared: expected true, got false"
replace with the bare scripts/**REDexit 1 — 4 failures, including the extension and dead-lead pins

⚠️ Reported rather than hidden: the FIRST ablation harness was a no-op — its perl replacer failed to compile on the glob metacharacters and changed nothing. The on-disk proof step caught it and the readings were voided; the table above is the re-run with an exact-literal replacer. Had that step been skipped, five green self-tests would have read as five passing ablations.

git diff --stat against the base: 2 files changed, 212 insertions(+), 1 deletion(-) — both under scripts/, so skip-changeset.

Serial check: every open PR's file list was read before editing; neither gate file is held. scripts/check-skills-token-ratchet.mjs (3 open PRs) and scripts/check-type-check-coverage.mjs (1) are held and were excluded from this sitting on that ground as well as on precision.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV


Generated by Claude Code

`scripts/pm/dispatch-gates.mjs` builds every dispatch's gate list by scanning a
gate's own source for the path literals it operates on, and "looks like a path"
there means "carries a separator". Both gates below seed a recursive walk at the
bare single-segment word `scripts`, which the extractor cannot see at all, so the
only literals recoverable from either file named individual artifacts: the six
scripts one gate's ledger cites by name, and two `owner/repo` action slugs plus
sandbox filenames in the other. An artifact roster is not a population -- a list
of the files that already exist can never contain the one added tomorrow -- so
both families walked all of `scripts/` and appeared on no card that edited any
of it.
Each now declares that population in its own module body under the
ROOT_DIR_WATCH_HINTS idiom, pinned in its own --self-test against the LIVE walk
in both directions: nothing walked left uncovered, nothing covered left unwalked.
One hint per admitted extension rather than the bare subtree, following
check-ratchet-remedy-authority.mjs at this same root -- `scripts/**` would name
both gates for the 91 JSON, Markdown and text files under the root that neither
one opens. An extension the filter admits but the tree does not yet hold is
deliberately absent, because a hint reaching nothing tracked is a dead lead the
consumer reports as a population; the pins redden the day such a file lands.
Measured on this tree with the derivation's own --residue, probe
scripts/check-nul-bytes.mjs: 14 matched families -> 16, Silent 148 -> 146. With
an outside probe (packages/metadata-protocol/src/protocol.ts) both stay Silent,
so the declaration does not over-claim.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33678836122 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: expected 'SIGKILL' to be null
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 20 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Merged via the queue into main with commit e5d530eSep 2, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14325-silent-gate-declarations-s1 branch September 2, 2026 20:52
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
…the sandbox-filename fix
12 of #14695's 14 unrecorded REFUSE-WIDE members are recorded in a new
CENSUS_REFUSE_WIDE table in scripts/pm/bare-root-worklist.mjs, each with its
own measured share and the base commit (2aa8456, the base #14325's own
census used) it was measured at. A new table rather than new TRIAGE rows:
TRIAGE is coupled to sweep(), which can only discover a bare-word population
literal assigned to a POPULATION_CONSTANT-shaped name, and none of these
families hold that shape (confirmed empirically: adding one to TRIAGE makes
--self-test fail STALE immediately). Two of the fourteen ("the two
packages/spec-filtered ones") are not recorded -- PR #14692's body, read in
full, does not name them, and guessing would fabricate a measurement no one
took.
Also folds in the small second half: scripts/check-whole-set-label-write.mjs's
three self-test sandbox filenames (scripts/w.mjs, scripts/writer.sh,
.github/workflows/w.yml) existed in no tracked tree and, spelled as bare
literals in a top-level export outside any selfTest()-shaped function, entered
the gate's own declared-population hint set as dead leads. Renamed to three
real, unrelated, already-tracked paths; no behaviour change to the gate's
verdict.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
… 14)
Follow-up to a36af67, which shipped 12 of 14 and left the two
`packages/spec`-filtered members ("check:error-code-provenance",
"check:objectui-pin-citations") as an open question -- the issue text's
claim that they were named in PR #14692's body with their shares did not
hold up against that body's actual text.
The filing session's own sitting-1 census artifacts supplied the two names
(both in its "root-wide, same class, no ledger row" bucket, members 13 and
14). Re-measured here by this table's own method rather than copied: strace
openat tracing against a 2aa8456 worktree, run via
`pnpm --filter @objectstack/spec run check:X` (tsx production leg). Both
land within 1 file of the filing session's own sitting-1 counts
(2070 vs 2069, and an exact 1192 vs 1192) -- corroborating the method a
second time, now on a tsx-run gate rather than a plain node one.
check:objectui-pin-citations (20.4%) lands below the issue's summarised
32-52% band; recorded as measured rather than forced into it.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
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

Development

Successfully merging this pull request may close these issues.

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 scripts/ population two Silent gate families walk but never named - #14692

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1
Sep 2, 2026
Merged

Declare the scripts/ population two Silent gate families walk but never named#14692
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Part of #14325 — sitting 1 of the per-gate half. The card stays open: the residue is not exhausted, and this sitting's measurement changes what the rest of it is.

What landed

Two gate families now declare the scripts/ population they walk but never named, in their own module body under the ROOT_DIR_WATCH_HINTS idiom, each pinned in its own --self-test — the shape PR #14188 and PR #14323 landed.

familydeclaredwhy it was silentresidue before ⇢ afterself-test pin
node scripts/check-self-test-wired.mjsscripts/**/*.mjs, scripts/**/*.mts, scripts/**/*.shcorpus root arrives as join(ROOT, 'scripts') — a bare single-segment word the extractor cannot see; its only other literals are the six scripts its ledger cites BY NAME (an artifact roster)Silent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.tsbattery population declaration, 7 cases, floor pinned
node scripts/check-whole-set-label-write.mjsscripts/**/*.mjs, scripts/**/*.ts, scripts/**/*.shtwo of three ROOTS carry a separator and were recovered; the third is the bare word scripts. The rest of its literals are two owner/repo action slugs and fixture sandbox filenamesSilent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.ts8 POPULATION cases in selfTest()

Measured with the derivation's own --residue, probe scripts/check-nul-bytes.mjs: 14 matched families ⇢ 16, Silent 148 ⇢ 146. With an outside probe the verdict is unchanged, so neither declaration over-claims.

One hint per admitted extension, not the bare subtree.check-ratchet-remedy-authority.mjs sets that precedent at this same root and its own self-test refuses the subtree spelling. scripts/** would name both gates for the 91 JSON, Markdown and text files under the root that neither one opens. The declared set is SET-EQUAL to each gate's live walk — 221 of 312 and 219 of 312 tracked files, nothing walked left uncovered, nothing covered left unwalked. An extension the filter admits but the tree does not yet HOLD (.js, .cjs, .yml, .yaml) is deliberately absent: a hint reaching nothing tracked is a dead lead the consumer reports as a population. The pins redden the day such a file lands.

⚠️ The finding this sitting is really for: the residue head is NOT a hint-line backlog

The card's own warning — reads are an upper bound — turns out to be the whole story, and the number is now measured rather than suspected.

Census re-derived on this branch's base (2aa8456cf), method as the card specifies: --residue for the Silent bucket, then every enumerating candidate run under an fs-tracing preload, compared against the literals extractWatchHints recovers from its own sources and judged with the derivation's own hintCovers. 202 families discovered, 132 Silent and non-self-test, 82 of those enumerate a directory, 49 read 5 or more undeclared tracked files.

Of those 49:

bucketndisposition
whole-tree6out of scope, #14189's channel — includes the three this census re-confirms (check-closing-keyword-parity, check-self-test-workflow-commands, check:watch-hint-literal)
declared this sitting2the only members with a NARROW, high-precision, undeclared population
root-wide, ledger already REFUSED13scripts/pm/bare-root-worklist.mjs records a verdict for each
root-wide, same class, no ledger row1432–52% of a 5837-file root — the identical trade, unrecorded
low precision (under 10%)14incidental or artifact reads; no honest subtree to declare

The head of the residue is the REFUSE-WIDE class, and this repo has already adjudicated it.scripts/pm/bare-root-worklist.mjs is a maintained, self-tested ledger of exactly this species and reports 0 untriaged rows. Every one of the four members the card source-confirmed as the natural head of sitting 1 is either recorded there as refused, or is unrecorded but measures into the same class:

  • check:engine-double-contract — REFUSE-WIDE on both roots (measured 90% / 84%), with the split refused by name
  • check:error-code-casing — REFUSE-WIDE, "same trade as engine-double-contract"
  • check:error-status-conformance — REFUSE-WIDE at 39%
  • check:route-envelopeno ledger row; walks join(ROOT, 'packages') over non-test .ts, measured here at 2138 undeclared reads = 36.6% of the root. Same class as check:authz-resolver, which IS recorded REFUSE-WIDE at 39%.

The ledger states the trade in its own words: a bare-root declaration there "would be TRUE, and is refused anyway: it names the gate for every card under a root the fleet already declares wholesale, so the matched column stops discriminating and restates 'run the farm', which CI does regardless." It also records the maintainer ruling of 2026-08-26 that split the spellable-but-undeclared rows by measured downstream pull — rows with a recorded consumer get the declaration, rows without stay deferred.

Sitting 2 cannot be "the next 8 by read count". Continuing down this order means declaring packages/** on gates whose recorded verdict refuses exactly that, which is a re-decision of a maintainer-ruled map, not the mechanical repair this card scoped. Three honest routes, for triage rather than for a dev to pick:

  1. Stop the per-gate half here. The narrow-subtree population the card describes was real and is now exhausted at two members; the rest of the residue is the width trade, already priced.
  2. Per-member consumer evidence. Take the 14 unrecorded root-wide members one at a time, and declare only where a MEASURED consumer exists (a card that ran a green local union and lost a CI round to that gate) — the criterion the 2026-08-26 ruling already uses. That is a p2-per-member shape, as the triage says.
  3. Record the 14 unrecorded members in the ledger so the class is closed by evidence rather than left looking like outstanding debt. This is a bare-root-worklist.mjs edit, so it belongs to a card that owns that file.

⛔ None of these is taken here. scripts/pm/dispatch-gates.mjs is untouched, as scoped.

Artifact-only by design, recorded rather than declared

check-self-test-wired and check-whole-set-label-write each ALSO name individual files — the ledger rows one cites, the action slugs and probe paths the other pins. Those stay as they are: they are artifacts the gate names, not a population it reads, and the new declaration sits beside them rather than replacing them. The 14 low-precision members above are the same shape at family scale and are recorded here, not declared.

Verification

Union derived in this worktree by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths passed — the script takes its own changeset), 17 commands, re-derived unchanged after merging origin/main. Run at be6800e2f:

  • 16 of 17 green, including check:watch-hint-literal (47 declarations across 4 rostered names), check:ratchet-remedy-authority, check:pm-dispatch-gates (VERDICT command-exit 0, dispatch-gates self-test 1240 cases pass), and node scripts/pm/bare-root-worklist.mjs --self-test ("none stale, none missing, none contradicted" — the new declarations create no fresh untriaged row and contradict no recorded verdict)
  • node scripts/check-declared-population-live.mjs — "158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8006 tracked file(s)"
  • both gates' production leg and --self-test leg green; check-self-test-wired prints "scope: 221 file(s) under scripts/", which is the declared set exactly
  • node scripts/check-test-completeness.mjs exits 3 = NOT MEASURED by its own design — it needs a CI test log and says so in its own output. Not a red.

Ablation — the pins are proved able to go red. Five legs, each mutating the committed declaration, each proved on disk by counting the removed and injected text before reading any result, each restored via git checkout HEAD and verified by git hash-object against the HEAD blob (both MATCH):

legexpectedobserved
drop scripts/**/*.shREDexit 1 — "a file this gate WALKS is left undeclared"
add scripts/**/*.jsonREDexit 1 — "a declared hint reaches nothing this gate walks — a dead lead"
rewrite as a computed .map() spellingREDexit 1 — "the declaration is not a single literal array of quoted strings"
drop scripts/**/*.tsREDexit 1 — "every file this gate walks under scripts/ is declared: expected true, got false"
replace with the bare scripts/**REDexit 1 — 4 failures, including the extension and dead-lead pins

⚠️ Reported rather than hidden: the FIRST ablation harness was a no-op — its perl replacer failed to compile on the glob metacharacters and changed nothing. The on-disk proof step caught it and the readings were voided; the table above is the re-run with an exact-literal replacer. Had that step been skipped, five green self-tests would have read as five passing ablations.

git diff --stat against the base: 2 files changed, 212 insertions(+), 1 deletion(-) — both under scripts/, so skip-changeset.

Serial check: every open PR's file list was read before editing; neither gate file is held. scripts/check-skills-token-ratchet.mjs (3 open PRs) and scripts/check-type-check-coverage.mjs (1) are held and were excluded from this sitting on that ground as well as on precision.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV


Generated by Claude Code

`scripts/pm/dispatch-gates.mjs` builds every dispatch's gate list by scanning a
gate's own source for the path literals it operates on, and "looks like a path"
there means "carries a separator". Both gates below seed a recursive walk at the
bare single-segment word `scripts`, which the extractor cannot see at all, so the
only literals recoverable from either file named individual artifacts: the six
scripts one gate's ledger cites by name, and two `owner/repo` action slugs plus
sandbox filenames in the other. An artifact roster is not a population -- a list
of the files that already exist can never contain the one added tomorrow -- so
both families walked all of `scripts/` and appeared on no card that edited any
of it.
Each now declares that population in its own module body under the
ROOT_DIR_WATCH_HINTS idiom, pinned in its own --self-test against the LIVE walk
in both directions: nothing walked left uncovered, nothing covered left unwalked.
One hint per admitted extension rather than the bare subtree, following
check-ratchet-remedy-authority.mjs at this same root -- `scripts/**` would name
both gates for the 91 JSON, Markdown and text files under the root that neither
one opens. An extension the filter admits but the tree does not yet hold is
deliberately absent, because a hint reaching nothing tracked is a dead lead the
consumer reports as a population; the pins redden the day such a file lands.
Measured on this tree with the derivation's own --residue, probe
scripts/check-nul-bytes.mjs: 14 matched families -> 16, Silent 148 -> 146. With
an outside probe (packages/metadata-protocol/src/protocol.ts) both stay Silent,
so the declaration does not over-claim.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33678836122 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: expected 'SIGKILL' to be null
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 20 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Merged via the queue into main with commit e5d530eSep 2, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14325-silent-gate-declarations-s1 branch September 2, 2026 20:52
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
…the sandbox-filename fix
12 of #14695's 14 unrecorded REFUSE-WIDE members are recorded in a new
CENSUS_REFUSE_WIDE table in scripts/pm/bare-root-worklist.mjs, each with its
own measured share and the base commit (2aa8456, the base #14325's own
census used) it was measured at. A new table rather than new TRIAGE rows:
TRIAGE is coupled to sweep(), which can only discover a bare-word population
literal assigned to a POPULATION_CONSTANT-shaped name, and none of these
families hold that shape (confirmed empirically: adding one to TRIAGE makes
--self-test fail STALE immediately). Two of the fourteen ("the two
packages/spec-filtered ones") are not recorded -- PR #14692's body, read in
full, does not name them, and guessing would fabricate a measurement no one
took.
Also folds in the small second half: scripts/check-whole-set-label-write.mjs's
three self-test sandbox filenames (scripts/w.mjs, scripts/writer.sh,
.github/workflows/w.yml) existed in no tracked tree and, spelled as bare
literals in a top-level export outside any selfTest()-shaped function, entered
the gate's own declared-population hint set as dead leads. Renamed to three
real, unrelated, already-tracked paths; no behaviour change to the gate's
verdict.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
… 14)
Follow-up to a36af67, which shipped 12 of 14 and left the two
`packages/spec`-filtered members ("check:error-code-provenance",
"check:objectui-pin-citations") as an open question -- the issue text's
claim that they were named in PR #14692's body with their shares did not
hold up against that body's actual text.
The filing session's own sitting-1 census artifacts supplied the two names
(both in its "root-wide, same class, no ledger row" bucket, members 13 and
14). Re-measured here by this table's own method rather than copied: strace
openat tracing against a 2aa8456 worktree, run via
`pnpm --filter @objectstack/spec run check:X` (tsx production leg). Both
land within 1 file of the filing session's own sitting-1 counts
(2070 vs 2069, and an exact 1192 vs 1192) -- corroborating the method a
second time, now on a tsx-run gate rather than a plain node one.
check:objectui-pin-citations (20.4%) lands below the issue's summarised
32-52% band; recorded as measured rather than forced into it.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
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

Development

Successfully merging this pull request may close these issues.

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 scripts/ population two Silent gate families walk but never named - #14692

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1
Sep 2, 2026
Merged

Declare the scripts/ population two Silent gate families walk but never named#14692
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Part of #14325 — sitting 1 of the per-gate half. The card stays open: the residue is not exhausted, and this sitting's measurement changes what the rest of it is.

What landed

Two gate families now declare the scripts/ population they walk but never named, in their own module body under the ROOT_DIR_WATCH_HINTS idiom, each pinned in its own --self-test — the shape PR #14188 and PR #14323 landed.

familydeclaredwhy it was silentresidue before ⇢ afterself-test pin
node scripts/check-self-test-wired.mjsscripts/**/*.mjs, scripts/**/*.mts, scripts/**/*.shcorpus root arrives as join(ROOT, 'scripts') — a bare single-segment word the extractor cannot see; its only other literals are the six scripts its ledger cites BY NAME (an artifact roster)Silent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.tsbattery population declaration, 7 cases, floor pinned
node scripts/check-whole-set-label-write.mjsscripts/**/*.mjs, scripts/**/*.ts, scripts/**/*.shtwo of three ROOTS carry a separator and were recovered; the third is the bare word scripts. The rest of its literals are two owner/repo action slugs and fixture sandbox filenamesSilent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.ts8 POPULATION cases in selfTest()

Measured with the derivation's own --residue, probe scripts/check-nul-bytes.mjs: 14 matched families ⇢ 16, Silent 148 ⇢ 146. With an outside probe the verdict is unchanged, so neither declaration over-claims.

One hint per admitted extension, not the bare subtree.check-ratchet-remedy-authority.mjs sets that precedent at this same root and its own self-test refuses the subtree spelling. scripts/** would name both gates for the 91 JSON, Markdown and text files under the root that neither one opens. The declared set is SET-EQUAL to each gate's live walk — 221 of 312 and 219 of 312 tracked files, nothing walked left uncovered, nothing covered left unwalked. An extension the filter admits but the tree does not yet HOLD (.js, .cjs, .yml, .yaml) is deliberately absent: a hint reaching nothing tracked is a dead lead the consumer reports as a population. The pins redden the day such a file lands.

⚠️ The finding this sitting is really for: the residue head is NOT a hint-line backlog

The card's own warning — reads are an upper bound — turns out to be the whole story, and the number is now measured rather than suspected.

Census re-derived on this branch's base (2aa8456cf), method as the card specifies: --residue for the Silent bucket, then every enumerating candidate run under an fs-tracing preload, compared against the literals extractWatchHints recovers from its own sources and judged with the derivation's own hintCovers. 202 families discovered, 132 Silent and non-self-test, 82 of those enumerate a directory, 49 read 5 or more undeclared tracked files.

Of those 49:

bucketndisposition
whole-tree6out of scope, #14189's channel — includes the three this census re-confirms (check-closing-keyword-parity, check-self-test-workflow-commands, check:watch-hint-literal)
declared this sitting2the only members with a NARROW, high-precision, undeclared population
root-wide, ledger already REFUSED13scripts/pm/bare-root-worklist.mjs records a verdict for each
root-wide, same class, no ledger row1432–52% of a 5837-file root — the identical trade, unrecorded
low precision (under 10%)14incidental or artifact reads; no honest subtree to declare

The head of the residue is the REFUSE-WIDE class, and this repo has already adjudicated it.scripts/pm/bare-root-worklist.mjs is a maintained, self-tested ledger of exactly this species and reports 0 untriaged rows. Every one of the four members the card source-confirmed as the natural head of sitting 1 is either recorded there as refused, or is unrecorded but measures into the same class:

  • check:engine-double-contract — REFUSE-WIDE on both roots (measured 90% / 84%), with the split refused by name
  • check:error-code-casing — REFUSE-WIDE, "same trade as engine-double-contract"
  • check:error-status-conformance — REFUSE-WIDE at 39%
  • check:route-envelopeno ledger row; walks join(ROOT, 'packages') over non-test .ts, measured here at 2138 undeclared reads = 36.6% of the root. Same class as check:authz-resolver, which IS recorded REFUSE-WIDE at 39%.

The ledger states the trade in its own words: a bare-root declaration there "would be TRUE, and is refused anyway: it names the gate for every card under a root the fleet already declares wholesale, so the matched column stops discriminating and restates 'run the farm', which CI does regardless." It also records the maintainer ruling of 2026-08-26 that split the spellable-but-undeclared rows by measured downstream pull — rows with a recorded consumer get the declaration, rows without stay deferred.

Sitting 2 cannot be "the next 8 by read count". Continuing down this order means declaring packages/** on gates whose recorded verdict refuses exactly that, which is a re-decision of a maintainer-ruled map, not the mechanical repair this card scoped. Three honest routes, for triage rather than for a dev to pick:

  1. Stop the per-gate half here. The narrow-subtree population the card describes was real and is now exhausted at two members; the rest of the residue is the width trade, already priced.
  2. Per-member consumer evidence. Take the 14 unrecorded root-wide members one at a time, and declare only where a MEASURED consumer exists (a card that ran a green local union and lost a CI round to that gate) — the criterion the 2026-08-26 ruling already uses. That is a p2-per-member shape, as the triage says.
  3. Record the 14 unrecorded members in the ledger so the class is closed by evidence rather than left looking like outstanding debt. This is a bare-root-worklist.mjs edit, so it belongs to a card that owns that file.

⛔ None of these is taken here. scripts/pm/dispatch-gates.mjs is untouched, as scoped.

Artifact-only by design, recorded rather than declared

check-self-test-wired and check-whole-set-label-write each ALSO name individual files — the ledger rows one cites, the action slugs and probe paths the other pins. Those stay as they are: they are artifacts the gate names, not a population it reads, and the new declaration sits beside them rather than replacing them. The 14 low-precision members above are the same shape at family scale and are recorded here, not declared.

Verification

Union derived in this worktree by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths passed — the script takes its own changeset), 17 commands, re-derived unchanged after merging origin/main. Run at be6800e2f:

  • 16 of 17 green, including check:watch-hint-literal (47 declarations across 4 rostered names), check:ratchet-remedy-authority, check:pm-dispatch-gates (VERDICT command-exit 0, dispatch-gates self-test 1240 cases pass), and node scripts/pm/bare-root-worklist.mjs --self-test ("none stale, none missing, none contradicted" — the new declarations create no fresh untriaged row and contradict no recorded verdict)
  • node scripts/check-declared-population-live.mjs — "158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8006 tracked file(s)"
  • both gates' production leg and --self-test leg green; check-self-test-wired prints "scope: 221 file(s) under scripts/", which is the declared set exactly
  • node scripts/check-test-completeness.mjs exits 3 = NOT MEASURED by its own design — it needs a CI test log and says so in its own output. Not a red.

Ablation — the pins are proved able to go red. Five legs, each mutating the committed declaration, each proved on disk by counting the removed and injected text before reading any result, each restored via git checkout HEAD and verified by git hash-object against the HEAD blob (both MATCH):

legexpectedobserved
drop scripts/**/*.shREDexit 1 — "a file this gate WALKS is left undeclared"
add scripts/**/*.jsonREDexit 1 — "a declared hint reaches nothing this gate walks — a dead lead"
rewrite as a computed .map() spellingREDexit 1 — "the declaration is not a single literal array of quoted strings"
drop scripts/**/*.tsREDexit 1 — "every file this gate walks under scripts/ is declared: expected true, got false"
replace with the bare scripts/**REDexit 1 — 4 failures, including the extension and dead-lead pins

⚠️ Reported rather than hidden: the FIRST ablation harness was a no-op — its perl replacer failed to compile on the glob metacharacters and changed nothing. The on-disk proof step caught it and the readings were voided; the table above is the re-run with an exact-literal replacer. Had that step been skipped, five green self-tests would have read as five passing ablations.

git diff --stat against the base: 2 files changed, 212 insertions(+), 1 deletion(-) — both under scripts/, so skip-changeset.

Serial check: every open PR's file list was read before editing; neither gate file is held. scripts/check-skills-token-ratchet.mjs (3 open PRs) and scripts/check-type-check-coverage.mjs (1) are held and were excluded from this sitting on that ground as well as on precision.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV


Generated by Claude Code

`scripts/pm/dispatch-gates.mjs` builds every dispatch's gate list by scanning a
gate's own source for the path literals it operates on, and "looks like a path"
there means "carries a separator". Both gates below seed a recursive walk at the
bare single-segment word `scripts`, which the extractor cannot see at all, so the
only literals recoverable from either file named individual artifacts: the six
scripts one gate's ledger cites by name, and two `owner/repo` action slugs plus
sandbox filenames in the other. An artifact roster is not a population -- a list
of the files that already exist can never contain the one added tomorrow -- so
both families walked all of `scripts/` and appeared on no card that edited any
of it.
Each now declares that population in its own module body under the
ROOT_DIR_WATCH_HINTS idiom, pinned in its own --self-test against the LIVE walk
in both directions: nothing walked left uncovered, nothing covered left unwalked.
One hint per admitted extension rather than the bare subtree, following
check-ratchet-remedy-authority.mjs at this same root -- `scripts/**` would name
both gates for the 91 JSON, Markdown and text files under the root that neither
one opens. An extension the filter admits but the tree does not yet hold is
deliberately absent, because a hint reaching nothing tracked is a dead lead the
consumer reports as a population; the pins redden the day such a file lands.
Measured on this tree with the derivation's own --residue, probe
scripts/check-nul-bytes.mjs: 14 matched families -> 16, Silent 148 -> 146. With
an outside probe (packages/metadata-protocol/src/protocol.ts) both stay Silent,
so the declaration does not over-claim.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33678836122 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: expected 'SIGKILL' to be null
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 20 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Merged via the queue into main with commit e5d530eSep 2, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14325-silent-gate-declarations-s1 branch September 2, 2026 20:52
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
…the sandbox-filename fix
12 of #14695's 14 unrecorded REFUSE-WIDE members are recorded in a new
CENSUS_REFUSE_WIDE table in scripts/pm/bare-root-worklist.mjs, each with its
own measured share and the base commit (2aa8456, the base #14325's own
census used) it was measured at. A new table rather than new TRIAGE rows:
TRIAGE is coupled to sweep(), which can only discover a bare-word population
literal assigned to a POPULATION_CONSTANT-shaped name, and none of these
families hold that shape (confirmed empirically: adding one to TRIAGE makes
--self-test fail STALE immediately). Two of the fourteen ("the two
packages/spec-filtered ones") are not recorded -- PR #14692's body, read in
full, does not name them, and guessing would fabricate a measurement no one
took.
Also folds in the small second half: scripts/check-whole-set-label-write.mjs's
three self-test sandbox filenames (scripts/w.mjs, scripts/writer.sh,
.github/workflows/w.yml) existed in no tracked tree and, spelled as bare
literals in a top-level export outside any selfTest()-shaped function, entered
the gate's own declared-population hint set as dead leads. Renamed to three
real, unrelated, already-tracked paths; no behaviour change to the gate's
verdict.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
… 14)
Follow-up to a36af67, which shipped 12 of 14 and left the two
`packages/spec`-filtered members ("check:error-code-provenance",
"check:objectui-pin-citations") as an open question -- the issue text's
claim that they were named in PR #14692's body with their shares did not
hold up against that body's actual text.
The filing session's own sitting-1 census artifacts supplied the two names
(both in its "root-wide, same class, no ledger row" bucket, members 13 and
14). Re-measured here by this table's own method rather than copied: strace
openat tracing against a 2aa8456 worktree, run via
`pnpm --filter @objectstack/spec run check:X` (tsx production leg). Both
land within 1 file of the filing session's own sitting-1 counts
(2070 vs 2069, and an exact 1192 vs 1192) -- corroborating the method a
second time, now on a tsx-run gate rather than a plain node one.
check:objectui-pin-citations (20.4%) lands below the issue's summarised
32-52% band; recorded as measured rather than forced into it.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
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

Development

Successfully merging this pull request may close these issues.

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 scripts/ population two Silent gate families walk but never named - #14692

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1
Sep 2, 2026
Merged

Declare the scripts/ population two Silent gate families walk but never named#14692
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Part of #14325 — sitting 1 of the per-gate half. The card stays open: the residue is not exhausted, and this sitting's measurement changes what the rest of it is.

What landed

Two gate families now declare the scripts/ population they walk but never named, in their own module body under the ROOT_DIR_WATCH_HINTS idiom, each pinned in its own --self-test — the shape PR #14188 and PR #14323 landed.

familydeclaredwhy it was silentresidue before ⇢ afterself-test pin
node scripts/check-self-test-wired.mjsscripts/**/*.mjs, scripts/**/*.mts, scripts/**/*.shcorpus root arrives as join(ROOT, 'scripts') — a bare single-segment word the extractor cannot see; its only other literals are the six scripts its ledger cites BY NAME (an artifact roster)Silent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.tsbattery population declaration, 7 cases, floor pinned
node scripts/check-whole-set-label-write.mjsscripts/**/*.mjs, scripts/**/*.ts, scripts/**/*.shtwo of three ROOTS carry a separator and were recovered; the third is the bare word scripts. The rest of its literals are two owner/repo action slugs and fixture sandbox filenamesSilent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.ts8 POPULATION cases in selfTest()

Measured with the derivation's own --residue, probe scripts/check-nul-bytes.mjs: 14 matched families ⇢ 16, Silent 148 ⇢ 146. With an outside probe the verdict is unchanged, so neither declaration over-claims.

One hint per admitted extension, not the bare subtree.check-ratchet-remedy-authority.mjs sets that precedent at this same root and its own self-test refuses the subtree spelling. scripts/** would name both gates for the 91 JSON, Markdown and text files under the root that neither one opens. The declared set is SET-EQUAL to each gate's live walk — 221 of 312 and 219 of 312 tracked files, nothing walked left uncovered, nothing covered left unwalked. An extension the filter admits but the tree does not yet HOLD (.js, .cjs, .yml, .yaml) is deliberately absent: a hint reaching nothing tracked is a dead lead the consumer reports as a population. The pins redden the day such a file lands.

⚠️ The finding this sitting is really for: the residue head is NOT a hint-line backlog

The card's own warning — reads are an upper bound — turns out to be the whole story, and the number is now measured rather than suspected.

Census re-derived on this branch's base (2aa8456cf), method as the card specifies: --residue for the Silent bucket, then every enumerating candidate run under an fs-tracing preload, compared against the literals extractWatchHints recovers from its own sources and judged with the derivation's own hintCovers. 202 families discovered, 132 Silent and non-self-test, 82 of those enumerate a directory, 49 read 5 or more undeclared tracked files.

Of those 49:

bucketndisposition
whole-tree6out of scope, #14189's channel — includes the three this census re-confirms (check-closing-keyword-parity, check-self-test-workflow-commands, check:watch-hint-literal)
declared this sitting2the only members with a NARROW, high-precision, undeclared population
root-wide, ledger already REFUSED13scripts/pm/bare-root-worklist.mjs records a verdict for each
root-wide, same class, no ledger row1432–52% of a 5837-file root — the identical trade, unrecorded
low precision (under 10%)14incidental or artifact reads; no honest subtree to declare

The head of the residue is the REFUSE-WIDE class, and this repo has already adjudicated it.scripts/pm/bare-root-worklist.mjs is a maintained, self-tested ledger of exactly this species and reports 0 untriaged rows. Every one of the four members the card source-confirmed as the natural head of sitting 1 is either recorded there as refused, or is unrecorded but measures into the same class:

  • check:engine-double-contract — REFUSE-WIDE on both roots (measured 90% / 84%), with the split refused by name
  • check:error-code-casing — REFUSE-WIDE, "same trade as engine-double-contract"
  • check:error-status-conformance — REFUSE-WIDE at 39%
  • check:route-envelopeno ledger row; walks join(ROOT, 'packages') over non-test .ts, measured here at 2138 undeclared reads = 36.6% of the root. Same class as check:authz-resolver, which IS recorded REFUSE-WIDE at 39%.

The ledger states the trade in its own words: a bare-root declaration there "would be TRUE, and is refused anyway: it names the gate for every card under a root the fleet already declares wholesale, so the matched column stops discriminating and restates 'run the farm', which CI does regardless." It also records the maintainer ruling of 2026-08-26 that split the spellable-but-undeclared rows by measured downstream pull — rows with a recorded consumer get the declaration, rows without stay deferred.

Sitting 2 cannot be "the next 8 by read count". Continuing down this order means declaring packages/** on gates whose recorded verdict refuses exactly that, which is a re-decision of a maintainer-ruled map, not the mechanical repair this card scoped. Three honest routes, for triage rather than for a dev to pick:

  1. Stop the per-gate half here. The narrow-subtree population the card describes was real and is now exhausted at two members; the rest of the residue is the width trade, already priced.
  2. Per-member consumer evidence. Take the 14 unrecorded root-wide members one at a time, and declare only where a MEASURED consumer exists (a card that ran a green local union and lost a CI round to that gate) — the criterion the 2026-08-26 ruling already uses. That is a p2-per-member shape, as the triage says.
  3. Record the 14 unrecorded members in the ledger so the class is closed by evidence rather than left looking like outstanding debt. This is a bare-root-worklist.mjs edit, so it belongs to a card that owns that file.

⛔ None of these is taken here. scripts/pm/dispatch-gates.mjs is untouched, as scoped.

Artifact-only by design, recorded rather than declared

check-self-test-wired and check-whole-set-label-write each ALSO name individual files — the ledger rows one cites, the action slugs and probe paths the other pins. Those stay as they are: they are artifacts the gate names, not a population it reads, and the new declaration sits beside them rather than replacing them. The 14 low-precision members above are the same shape at family scale and are recorded here, not declared.

Verification

Union derived in this worktree by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths passed — the script takes its own changeset), 17 commands, re-derived unchanged after merging origin/main. Run at be6800e2f:

  • 16 of 17 green, including check:watch-hint-literal (47 declarations across 4 rostered names), check:ratchet-remedy-authority, check:pm-dispatch-gates (VERDICT command-exit 0, dispatch-gates self-test 1240 cases pass), and node scripts/pm/bare-root-worklist.mjs --self-test ("none stale, none missing, none contradicted" — the new declarations create no fresh untriaged row and contradict no recorded verdict)
  • node scripts/check-declared-population-live.mjs — "158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8006 tracked file(s)"
  • both gates' production leg and --self-test leg green; check-self-test-wired prints "scope: 221 file(s) under scripts/", which is the declared set exactly
  • node scripts/check-test-completeness.mjs exits 3 = NOT MEASURED by its own design — it needs a CI test log and says so in its own output. Not a red.

Ablation — the pins are proved able to go red. Five legs, each mutating the committed declaration, each proved on disk by counting the removed and injected text before reading any result, each restored via git checkout HEAD and verified by git hash-object against the HEAD blob (both MATCH):

legexpectedobserved
drop scripts/**/*.shREDexit 1 — "a file this gate WALKS is left undeclared"
add scripts/**/*.jsonREDexit 1 — "a declared hint reaches nothing this gate walks — a dead lead"
rewrite as a computed .map() spellingREDexit 1 — "the declaration is not a single literal array of quoted strings"
drop scripts/**/*.tsREDexit 1 — "every file this gate walks under scripts/ is declared: expected true, got false"
replace with the bare scripts/**REDexit 1 — 4 failures, including the extension and dead-lead pins

⚠️ Reported rather than hidden: the FIRST ablation harness was a no-op — its perl replacer failed to compile on the glob metacharacters and changed nothing. The on-disk proof step caught it and the readings were voided; the table above is the re-run with an exact-literal replacer. Had that step been skipped, five green self-tests would have read as five passing ablations.

git diff --stat against the base: 2 files changed, 212 insertions(+), 1 deletion(-) — both under scripts/, so skip-changeset.

Serial check: every open PR's file list was read before editing; neither gate file is held. scripts/check-skills-token-ratchet.mjs (3 open PRs) and scripts/check-type-check-coverage.mjs (1) are held and were excluded from this sitting on that ground as well as on precision.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV


Generated by Claude Code

`scripts/pm/dispatch-gates.mjs` builds every dispatch's gate list by scanning a
gate's own source for the path literals it operates on, and "looks like a path"
there means "carries a separator". Both gates below seed a recursive walk at the
bare single-segment word `scripts`, which the extractor cannot see at all, so the
only literals recoverable from either file named individual artifacts: the six
scripts one gate's ledger cites by name, and two `owner/repo` action slugs plus
sandbox filenames in the other. An artifact roster is not a population -- a list
of the files that already exist can never contain the one added tomorrow -- so
both families walked all of `scripts/` and appeared on no card that edited any
of it.
Each now declares that population in its own module body under the
ROOT_DIR_WATCH_HINTS idiom, pinned in its own --self-test against the LIVE walk
in both directions: nothing walked left uncovered, nothing covered left unwalked.
One hint per admitted extension rather than the bare subtree, following
check-ratchet-remedy-authority.mjs at this same root -- `scripts/**` would name
both gates for the 91 JSON, Markdown and text files under the root that neither
one opens. An extension the filter admits but the tree does not yet hold is
deliberately absent, because a hint reaching nothing tracked is a dead lead the
consumer reports as a population; the pins redden the day such a file lands.
Measured on this tree with the derivation's own --residue, probe
scripts/check-nul-bytes.mjs: 14 matched families -> 16, Silent 148 -> 146. With
an outside probe (packages/metadata-protocol/src/protocol.ts) both stay Silent,
so the declaration does not over-claim.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33678836122 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: expected 'SIGKILL' to be null
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 20 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Merged via the queue into main with commit e5d530eSep 2, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14325-silent-gate-declarations-s1 branch September 2, 2026 20:52
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
…the sandbox-filename fix
12 of #14695's 14 unrecorded REFUSE-WIDE members are recorded in a new
CENSUS_REFUSE_WIDE table in scripts/pm/bare-root-worklist.mjs, each with its
own measured share and the base commit (2aa8456, the base #14325's own
census used) it was measured at. A new table rather than new TRIAGE rows:
TRIAGE is coupled to sweep(), which can only discover a bare-word population
literal assigned to a POPULATION_CONSTANT-shaped name, and none of these
families hold that shape (confirmed empirically: adding one to TRIAGE makes
--self-test fail STALE immediately). Two of the fourteen ("the two
packages/spec-filtered ones") are not recorded -- PR #14692's body, read in
full, does not name them, and guessing would fabricate a measurement no one
took.
Also folds in the small second half: scripts/check-whole-set-label-write.mjs's
three self-test sandbox filenames (scripts/w.mjs, scripts/writer.sh,
.github/workflows/w.yml) existed in no tracked tree and, spelled as bare
literals in a top-level export outside any selfTest()-shaped function, entered
the gate's own declared-population hint set as dead leads. Renamed to three
real, unrelated, already-tracked paths; no behaviour change to the gate's
verdict.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
… 14)
Follow-up to a36af67, which shipped 12 of 14 and left the two
`packages/spec`-filtered members ("check:error-code-provenance",
"check:objectui-pin-citations") as an open question -- the issue text's
claim that they were named in PR #14692's body with their shares did not
hold up against that body's actual text.
The filing session's own sitting-1 census artifacts supplied the two names
(both in its "root-wide, same class, no ledger row" bucket, members 13 and
14). Re-measured here by this table's own method rather than copied: strace
openat tracing against a 2aa8456 worktree, run via
`pnpm --filter @objectstack/spec run check:X` (tsx production leg). Both
land within 1 file of the filing session's own sitting-1 counts
(2070 vs 2069, and an exact 1192 vs 1192) -- corroborating the method a
second time, now on a tsx-run gate rather than a plain node one.
check:objectui-pin-citations (20.4%) lands below the issue's summarised
32-52% band; recorded as measured rather than forced into it.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
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

Development

Successfully merging this pull request may close these issues.

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 scripts/ population two Silent gate families walk but never named - #14692

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1
Sep 2, 2026
Merged

Declare the scripts/ population two Silent gate families walk but never named#14692
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Part of #14325 — sitting 1 of the per-gate half. The card stays open: the residue is not exhausted, and this sitting's measurement changes what the rest of it is.

What landed

Two gate families now declare the scripts/ population they walk but never named, in their own module body under the ROOT_DIR_WATCH_HINTS idiom, each pinned in its own --self-test — the shape PR #14188 and PR #14323 landed.

familydeclaredwhy it was silentresidue before ⇢ afterself-test pin
node scripts/check-self-test-wired.mjsscripts/**/*.mjs, scripts/**/*.mts, scripts/**/*.shcorpus root arrives as join(ROOT, 'scripts') — a bare single-segment word the extractor cannot see; its only other literals are the six scripts its ledger cites BY NAME (an artifact roster)Silent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.tsbattery population declaration, 7 cases, floor pinned
node scripts/check-whole-set-label-write.mjsscripts/**/*.mjs, scripts/**/*.ts, scripts/**/*.shtwo of three ROOTS carry a separator and were recovered; the third is the bare word scripts. The rest of its literals are two owner/repo action slugs and fixture sandbox filenamesSilent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.ts8 POPULATION cases in selfTest()

Measured with the derivation's own --residue, probe scripts/check-nul-bytes.mjs: 14 matched families ⇢ 16, Silent 148 ⇢ 146. With an outside probe the verdict is unchanged, so neither declaration over-claims.

One hint per admitted extension, not the bare subtree.check-ratchet-remedy-authority.mjs sets that precedent at this same root and its own self-test refuses the subtree spelling. scripts/** would name both gates for the 91 JSON, Markdown and text files under the root that neither one opens. The declared set is SET-EQUAL to each gate's live walk — 221 of 312 and 219 of 312 tracked files, nothing walked left uncovered, nothing covered left unwalked. An extension the filter admits but the tree does not yet HOLD (.js, .cjs, .yml, .yaml) is deliberately absent: a hint reaching nothing tracked is a dead lead the consumer reports as a population. The pins redden the day such a file lands.

⚠️ The finding this sitting is really for: the residue head is NOT a hint-line backlog

The card's own warning — reads are an upper bound — turns out to be the whole story, and the number is now measured rather than suspected.

Census re-derived on this branch's base (2aa8456cf), method as the card specifies: --residue for the Silent bucket, then every enumerating candidate run under an fs-tracing preload, compared against the literals extractWatchHints recovers from its own sources and judged with the derivation's own hintCovers. 202 families discovered, 132 Silent and non-self-test, 82 of those enumerate a directory, 49 read 5 or more undeclared tracked files.

Of those 49:

bucketndisposition
whole-tree6out of scope, #14189's channel — includes the three this census re-confirms (check-closing-keyword-parity, check-self-test-workflow-commands, check:watch-hint-literal)
declared this sitting2the only members with a NARROW, high-precision, undeclared population
root-wide, ledger already REFUSED13scripts/pm/bare-root-worklist.mjs records a verdict for each
root-wide, same class, no ledger row1432–52% of a 5837-file root — the identical trade, unrecorded
low precision (under 10%)14incidental or artifact reads; no honest subtree to declare

The head of the residue is the REFUSE-WIDE class, and this repo has already adjudicated it.scripts/pm/bare-root-worklist.mjs is a maintained, self-tested ledger of exactly this species and reports 0 untriaged rows. Every one of the four members the card source-confirmed as the natural head of sitting 1 is either recorded there as refused, or is unrecorded but measures into the same class:

  • check:engine-double-contract — REFUSE-WIDE on both roots (measured 90% / 84%), with the split refused by name
  • check:error-code-casing — REFUSE-WIDE, "same trade as engine-double-contract"
  • check:error-status-conformance — REFUSE-WIDE at 39%
  • check:route-envelopeno ledger row; walks join(ROOT, 'packages') over non-test .ts, measured here at 2138 undeclared reads = 36.6% of the root. Same class as check:authz-resolver, which IS recorded REFUSE-WIDE at 39%.

The ledger states the trade in its own words: a bare-root declaration there "would be TRUE, and is refused anyway: it names the gate for every card under a root the fleet already declares wholesale, so the matched column stops discriminating and restates 'run the farm', which CI does regardless." It also records the maintainer ruling of 2026-08-26 that split the spellable-but-undeclared rows by measured downstream pull — rows with a recorded consumer get the declaration, rows without stay deferred.

Sitting 2 cannot be "the next 8 by read count". Continuing down this order means declaring packages/** on gates whose recorded verdict refuses exactly that, which is a re-decision of a maintainer-ruled map, not the mechanical repair this card scoped. Three honest routes, for triage rather than for a dev to pick:

  1. Stop the per-gate half here. The narrow-subtree population the card describes was real and is now exhausted at two members; the rest of the residue is the width trade, already priced.
  2. Per-member consumer evidence. Take the 14 unrecorded root-wide members one at a time, and declare only where a MEASURED consumer exists (a card that ran a green local union and lost a CI round to that gate) — the criterion the 2026-08-26 ruling already uses. That is a p2-per-member shape, as the triage says.
  3. Record the 14 unrecorded members in the ledger so the class is closed by evidence rather than left looking like outstanding debt. This is a bare-root-worklist.mjs edit, so it belongs to a card that owns that file.

⛔ None of these is taken here. scripts/pm/dispatch-gates.mjs is untouched, as scoped.

Artifact-only by design, recorded rather than declared

check-self-test-wired and check-whole-set-label-write each ALSO name individual files — the ledger rows one cites, the action slugs and probe paths the other pins. Those stay as they are: they are artifacts the gate names, not a population it reads, and the new declaration sits beside them rather than replacing them. The 14 low-precision members above are the same shape at family scale and are recorded here, not declared.

Verification

Union derived in this worktree by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths passed — the script takes its own changeset), 17 commands, re-derived unchanged after merging origin/main. Run at be6800e2f:

  • 16 of 17 green, including check:watch-hint-literal (47 declarations across 4 rostered names), check:ratchet-remedy-authority, check:pm-dispatch-gates (VERDICT command-exit 0, dispatch-gates self-test 1240 cases pass), and node scripts/pm/bare-root-worklist.mjs --self-test ("none stale, none missing, none contradicted" — the new declarations create no fresh untriaged row and contradict no recorded verdict)
  • node scripts/check-declared-population-live.mjs — "158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8006 tracked file(s)"
  • both gates' production leg and --self-test leg green; check-self-test-wired prints "scope: 221 file(s) under scripts/", which is the declared set exactly
  • node scripts/check-test-completeness.mjs exits 3 = NOT MEASURED by its own design — it needs a CI test log and says so in its own output. Not a red.

Ablation — the pins are proved able to go red. Five legs, each mutating the committed declaration, each proved on disk by counting the removed and injected text before reading any result, each restored via git checkout HEAD and verified by git hash-object against the HEAD blob (both MATCH):

legexpectedobserved
drop scripts/**/*.shREDexit 1 — "a file this gate WALKS is left undeclared"
add scripts/**/*.jsonREDexit 1 — "a declared hint reaches nothing this gate walks — a dead lead"
rewrite as a computed .map() spellingREDexit 1 — "the declaration is not a single literal array of quoted strings"
drop scripts/**/*.tsREDexit 1 — "every file this gate walks under scripts/ is declared: expected true, got false"
replace with the bare scripts/**REDexit 1 — 4 failures, including the extension and dead-lead pins

⚠️ Reported rather than hidden: the FIRST ablation harness was a no-op — its perl replacer failed to compile on the glob metacharacters and changed nothing. The on-disk proof step caught it and the readings were voided; the table above is the re-run with an exact-literal replacer. Had that step been skipped, five green self-tests would have read as five passing ablations.

git diff --stat against the base: 2 files changed, 212 insertions(+), 1 deletion(-) — both under scripts/, so skip-changeset.

Serial check: every open PR's file list was read before editing; neither gate file is held. scripts/check-skills-token-ratchet.mjs (3 open PRs) and scripts/check-type-check-coverage.mjs (1) are held and were excluded from this sitting on that ground as well as on precision.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV


Generated by Claude Code

`scripts/pm/dispatch-gates.mjs` builds every dispatch's gate list by scanning a
gate's own source for the path literals it operates on, and "looks like a path"
there means "carries a separator". Both gates below seed a recursive walk at the
bare single-segment word `scripts`, which the extractor cannot see at all, so the
only literals recoverable from either file named individual artifacts: the six
scripts one gate's ledger cites by name, and two `owner/repo` action slugs plus
sandbox filenames in the other. An artifact roster is not a population -- a list
of the files that already exist can never contain the one added tomorrow -- so
both families walked all of `scripts/` and appeared on no card that edited any
of it.
Each now declares that population in its own module body under the
ROOT_DIR_WATCH_HINTS idiom, pinned in its own --self-test against the LIVE walk
in both directions: nothing walked left uncovered, nothing covered left unwalked.
One hint per admitted extension rather than the bare subtree, following
check-ratchet-remedy-authority.mjs at this same root -- `scripts/**` would name
both gates for the 91 JSON, Markdown and text files under the root that neither
one opens. An extension the filter admits but the tree does not yet hold is
deliberately absent, because a hint reaching nothing tracked is a dead lead the
consumer reports as a population; the pins redden the day such a file lands.
Measured on this tree with the derivation's own --residue, probe
scripts/check-nul-bytes.mjs: 14 matched families -> 16, Silent 148 -> 146. With
an outside probe (packages/metadata-protocol/src/protocol.ts) both stay Silent,
so the declaration does not over-claim.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33678836122 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: expected 'SIGKILL' to be null
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 20 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Merged via the queue into main with commit e5d530eSep 2, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14325-silent-gate-declarations-s1 branch September 2, 2026 20:52
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
…the sandbox-filename fix
12 of #14695's 14 unrecorded REFUSE-WIDE members are recorded in a new
CENSUS_REFUSE_WIDE table in scripts/pm/bare-root-worklist.mjs, each with its
own measured share and the base commit (2aa8456, the base #14325's own
census used) it was measured at. A new table rather than new TRIAGE rows:
TRIAGE is coupled to sweep(), which can only discover a bare-word population
literal assigned to a POPULATION_CONSTANT-shaped name, and none of these
families hold that shape (confirmed empirically: adding one to TRIAGE makes
--self-test fail STALE immediately). Two of the fourteen ("the two
packages/spec-filtered ones") are not recorded -- PR #14692's body, read in
full, does not name them, and guessing would fabricate a measurement no one
took.
Also folds in the small second half: scripts/check-whole-set-label-write.mjs's
three self-test sandbox filenames (scripts/w.mjs, scripts/writer.sh,
.github/workflows/w.yml) existed in no tracked tree and, spelled as bare
literals in a top-level export outside any selfTest()-shaped function, entered
the gate's own declared-population hint set as dead leads. Renamed to three
real, unrelated, already-tracked paths; no behaviour change to the gate's
verdict.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
… 14)
Follow-up to a36af67, which shipped 12 of 14 and left the two
`packages/spec`-filtered members ("check:error-code-provenance",
"check:objectui-pin-citations") as an open question -- the issue text's
claim that they were named in PR #14692's body with their shares did not
hold up against that body's actual text.
The filing session's own sitting-1 census artifacts supplied the two names
(both in its "root-wide, same class, no ledger row" bucket, members 13 and
14). Re-measured here by this table's own method rather than copied: strace
openat tracing against a 2aa8456 worktree, run via
`pnpm --filter @objectstack/spec run check:X` (tsx production leg). Both
land within 1 file of the filing session's own sitting-1 counts
(2070 vs 2069, and an exact 1192 vs 1192) -- corroborating the method a
second time, now on a tsx-run gate rather than a plain node one.
check:objectui-pin-citations (20.4%) lands below the issue's summarised
32-52% band; recorded as measured rather than forced into it.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
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

Development

Successfully merging this pull request may close these issues.

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 scripts/ population two Silent gate families walk but never named - #14692

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1
Sep 2, 2026
Merged

Declare the scripts/ population two Silent gate families walk but never named#14692
baozhoutao merged 2 commits into
mainfrom
claude/issue-14325-silent-gate-declarations-s1

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Part of #14325 — sitting 1 of the per-gate half. The card stays open: the residue is not exhausted, and this sitting's measurement changes what the rest of it is.

What landed

Two gate families now declare the scripts/ population they walk but never named, in their own module body under the ROOT_DIR_WATCH_HINTS idiom, each pinned in its own --self-test — the shape PR #14188 and PR #14323 landed.

familydeclaredwhy it was silentresidue before ⇢ afterself-test pin
node scripts/check-self-test-wired.mjsscripts/**/*.mjs, scripts/**/*.mts, scripts/**/*.shcorpus root arrives as join(ROOT, 'scripts') — a bare single-segment word the extractor cannot see; its only other literals are the six scripts its ledger cites BY NAME (an artifact roster)Silent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.tsbattery population declaration, 7 cases, floor pinned
node scripts/check-whole-set-label-write.mjsscripts/**/*.mjs, scripts/**/*.ts, scripts/**/*.shtwo of three ROOTS carry a separator and were recovered; the third is the bare word scripts. The rest of its literals are two owner/repo action slugs and fixture sandbox filenamesSilent ⇢ matched on scripts/check-nul-bytes.mjs; still Silent on packages/metadata-protocol/src/protocol.ts8 POPULATION cases in selfTest()

Measured with the derivation's own --residue, probe scripts/check-nul-bytes.mjs: 14 matched families ⇢ 16, Silent 148 ⇢ 146. With an outside probe the verdict is unchanged, so neither declaration over-claims.

One hint per admitted extension, not the bare subtree.check-ratchet-remedy-authority.mjs sets that precedent at this same root and its own self-test refuses the subtree spelling. scripts/** would name both gates for the 91 JSON, Markdown and text files under the root that neither one opens. The declared set is SET-EQUAL to each gate's live walk — 221 of 312 and 219 of 312 tracked files, nothing walked left uncovered, nothing covered left unwalked. An extension the filter admits but the tree does not yet HOLD (.js, .cjs, .yml, .yaml) is deliberately absent: a hint reaching nothing tracked is a dead lead the consumer reports as a population. The pins redden the day such a file lands.

⚠️ The finding this sitting is really for: the residue head is NOT a hint-line backlog

The card's own warning — reads are an upper bound — turns out to be the whole story, and the number is now measured rather than suspected.

Census re-derived on this branch's base (2aa8456cf), method as the card specifies: --residue for the Silent bucket, then every enumerating candidate run under an fs-tracing preload, compared against the literals extractWatchHints recovers from its own sources and judged with the derivation's own hintCovers. 202 families discovered, 132 Silent and non-self-test, 82 of those enumerate a directory, 49 read 5 or more undeclared tracked files.

Of those 49:

bucketndisposition
whole-tree6out of scope, #14189's channel — includes the three this census re-confirms (check-closing-keyword-parity, check-self-test-workflow-commands, check:watch-hint-literal)
declared this sitting2the only members with a NARROW, high-precision, undeclared population
root-wide, ledger already REFUSED13scripts/pm/bare-root-worklist.mjs records a verdict for each
root-wide, same class, no ledger row1432–52% of a 5837-file root — the identical trade, unrecorded
low precision (under 10%)14incidental or artifact reads; no honest subtree to declare

The head of the residue is the REFUSE-WIDE class, and this repo has already adjudicated it.scripts/pm/bare-root-worklist.mjs is a maintained, self-tested ledger of exactly this species and reports 0 untriaged rows. Every one of the four members the card source-confirmed as the natural head of sitting 1 is either recorded there as refused, or is unrecorded but measures into the same class:

  • check:engine-double-contract — REFUSE-WIDE on both roots (measured 90% / 84%), with the split refused by name
  • check:error-code-casing — REFUSE-WIDE, "same trade as engine-double-contract"
  • check:error-status-conformance — REFUSE-WIDE at 39%
  • check:route-envelopeno ledger row; walks join(ROOT, 'packages') over non-test .ts, measured here at 2138 undeclared reads = 36.6% of the root. Same class as check:authz-resolver, which IS recorded REFUSE-WIDE at 39%.

The ledger states the trade in its own words: a bare-root declaration there "would be TRUE, and is refused anyway: it names the gate for every card under a root the fleet already declares wholesale, so the matched column stops discriminating and restates 'run the farm', which CI does regardless." It also records the maintainer ruling of 2026-08-26 that split the spellable-but-undeclared rows by measured downstream pull — rows with a recorded consumer get the declaration, rows without stay deferred.

Sitting 2 cannot be "the next 8 by read count". Continuing down this order means declaring packages/** on gates whose recorded verdict refuses exactly that, which is a re-decision of a maintainer-ruled map, not the mechanical repair this card scoped. Three honest routes, for triage rather than for a dev to pick:

  1. Stop the per-gate half here. The narrow-subtree population the card describes was real and is now exhausted at two members; the rest of the residue is the width trade, already priced.
  2. Per-member consumer evidence. Take the 14 unrecorded root-wide members one at a time, and declare only where a MEASURED consumer exists (a card that ran a green local union and lost a CI round to that gate) — the criterion the 2026-08-26 ruling already uses. That is a p2-per-member shape, as the triage says.
  3. Record the 14 unrecorded members in the ledger so the class is closed by evidence rather than left looking like outstanding debt. This is a bare-root-worklist.mjs edit, so it belongs to a card that owns that file.

⛔ None of these is taken here. scripts/pm/dispatch-gates.mjs is untouched, as scoped.

Artifact-only by design, recorded rather than declared

check-self-test-wired and check-whole-set-label-write each ALSO name individual files — the ledger rows one cites, the action slugs and probe paths the other pins. Those stay as they are: they are artifacts the gate names, not a population it reads, and the new declaration sits beside them rather than replacing them. The 14 low-precision members above are the same shape at family scale and are recorded here, not declared.

Verification

Union derived in this worktree by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths passed — the script takes its own changeset), 17 commands, re-derived unchanged after merging origin/main. Run at be6800e2f:

  • 16 of 17 green, including check:watch-hint-literal (47 declarations across 4 rostered names), check:ratchet-remedy-authority, check:pm-dispatch-gates (VERDICT command-exit 0, dispatch-gates self-test 1240 cases pass), and node scripts/pm/bare-root-worklist.mjs --self-test ("none stale, none missing, none contradicted" — the new declarations create no fresh untriaged row and contradict no recorded verdict)
  • node scripts/check-declared-population-live.mjs — "158 of 202 famil(ies) declare a path population, and every one of them reaches this tree's 8006 tracked file(s)"
  • both gates' production leg and --self-test leg green; check-self-test-wired prints "scope: 221 file(s) under scripts/", which is the declared set exactly
  • node scripts/check-test-completeness.mjs exits 3 = NOT MEASURED by its own design — it needs a CI test log and says so in its own output. Not a red.

Ablation — the pins are proved able to go red. Five legs, each mutating the committed declaration, each proved on disk by counting the removed and injected text before reading any result, each restored via git checkout HEAD and verified by git hash-object against the HEAD blob (both MATCH):

legexpectedobserved
drop scripts/**/*.shREDexit 1 — "a file this gate WALKS is left undeclared"
add scripts/**/*.jsonREDexit 1 — "a declared hint reaches nothing this gate walks — a dead lead"
rewrite as a computed .map() spellingREDexit 1 — "the declaration is not a single literal array of quoted strings"
drop scripts/**/*.tsREDexit 1 — "every file this gate walks under scripts/ is declared: expected true, got false"
replace with the bare scripts/**REDexit 1 — 4 failures, including the extension and dead-lead pins

⚠️ Reported rather than hidden: the FIRST ablation harness was a no-op — its perl replacer failed to compile on the glob metacharacters and changed nothing. The on-disk proof step caught it and the readings were voided; the table above is the re-run with an exact-literal replacer. Had that step been skipped, five green self-tests would have read as five passing ablations.

git diff --stat against the base: 2 files changed, 212 insertions(+), 1 deletion(-) — both under scripts/, so skip-changeset.

Serial check: every open PR's file list was read before editing; neither gate file is held. scripts/check-skills-token-ratchet.mjs (3 open PRs) and scripts/check-type-check-coverage.mjs (1) are held and were excluded from this sitting on that ground as well as on precision.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV


Generated by Claude Code

`scripts/pm/dispatch-gates.mjs` builds every dispatch's gate list by scanning a
gate's own source for the path literals it operates on, and "looks like a path"
there means "carries a separator". Both gates below seed a recursive walk at the
bare single-segment word `scripts`, which the extractor cannot see at all, so the
only literals recoverable from either file named individual artifacts: the six
scripts one gate's ledger cites by name, and two `owner/repo` action slugs plus
sandbox filenames in the other. An artifact roster is not a population -- a list
of the files that already exist can never contain the one added tomorrow -- so
both families walked all of `scripts/` and appeared on no card that edited any
of it.
Each now declares that population in its own module body under the
ROOT_DIR_WATCH_HINTS idiom, pinned in its own --self-test against the LIVE walk
in both directions: nothing walked left uncovered, nothing covered left unwalked.
One hint per admitted extension rather than the bare subtree, following
check-ratchet-remedy-authority.mjs at this same root -- `scripts/**` would name
both gates for the 91 JSON, Markdown and text files under the root that neither
one opens. An extension the filter admits but the tree does not yet hold is
deliberately absent, because a hint reaching nothing tracked is a dead lead the
consumer reports as a population; the pins redden the day such a file lands.
Measured on this tree with the derivation's own --residue, probe
scripts/check-nul-bytes.mjs: 14 matched families -> 16, Silent 148 -> 146. With
an outside probe (packages/metadata-protocol/src/protocol.ts) both stay Silent,
so the declaration does not over-claim.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33678836122 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: expected 'SIGKILL' to be null
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 20 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Merged via the queue into main with commit e5d530eSep 2, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14325-silent-gate-declarations-s1 branch September 2, 2026 20:52
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
…the sandbox-filename fix
12 of #14695's 14 unrecorded REFUSE-WIDE members are recorded in a new
CENSUS_REFUSE_WIDE table in scripts/pm/bare-root-worklist.mjs, each with its
own measured share and the base commit (2aa8456, the base #14325's own
census used) it was measured at. A new table rather than new TRIAGE rows:
TRIAGE is coupled to sweep(), which can only discover a bare-word population
literal assigned to a POPULATION_CONSTANT-shaped name, and none of these
families hold that shape (confirmed empirically: adding one to TRIAGE makes
--self-test fail STALE immediately). Two of the fourteen ("the two
packages/spec-filtered ones") are not recorded -- PR #14692's body, read in
full, does not name them, and guessing would fabricate a measurement no one
took.
Also folds in the small second half: scripts/check-whole-set-label-write.mjs's
three self-test sandbox filenames (scripts/w.mjs, scripts/writer.sh,
.github/workflows/w.yml) existed in no tracked tree and, spelled as bare
literals in a top-level export outside any selfTest()-shaped function, entered
the gate's own declared-population hint set as dead leads. Renamed to three
real, unrelated, already-tracked paths; no behaviour change to the gate's
verdict.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
… 14)
Follow-up to a36af67, which shipped 12 of 14 and left the two
`packages/spec`-filtered members ("check:error-code-provenance",
"check:objectui-pin-citations") as an open question -- the issue text's
claim that they were named in PR #14692's body with their shares did not
hold up against that body's actual text.
The filing session's own sitting-1 census artifacts supplied the two names
(both in its "root-wide, same class, no ledger row" bucket, members 13 and
14). Re-measured here by this table's own method rather than copied: strace
openat tracing against a 2aa8456 worktree, run via
`pnpm --filter @objectstack/spec run check:X` (tsx production leg). Both
land within 1 file of the filing session's own sitting-1 counts
(2070 vs 2069, and an exact 1192 vs 1192) -- corroborating the method a
second time, now on a tsx-run gate rather than a plain node one.
check:objectui-pin-citations (20.4%) lands below the issue's summarised
32-52% band; recorded as measured rather than forced into it.
Fixes#14695
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
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

Development

Successfully merging this pull request may close these issues.

2 participants

@baozhoutao@claude