You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[finding] dispatch-gates.mjs is a followable non-gate module, so its join bases and tier globs are inheritable — 2553 fabricated pairs for the next gate that imports it #11556
Measured while landing #11404 (PR #11554, the --self-test invocation matcher). Filed unassigned; nothing is red today — the one live instance is closed inside that PR, and this card is about the latent half it does not close.
What was measured
scripts/pm/dispatch-gates.mjs is not a discovered gate FILE. check:pm-dispatch-gates resolves to scripts/pm/check-dispatch-gates.mjs, which reaches the tool by spawnSync, never by import — so discoverFamilies' "never follow a module that is itself a gate file" rule does not protect it.
Its module body yields 9 watch hints under today's extractor:
Against 6465 tracked files those cover 2553 of them. Only .github/workflows is something the tool reads as a population; packages/plugins, packages/drivers and packages/services are the bases its package resolver joins, and packages/spec/src/** is a tier glob the file's own self-test pins as inert for gate matching.
So any gate script that statically imports ./dispatch-gates.mjs inherits 2553 (gate, file) pairs of population it never opens. Measured live: scripts/pm/bare-root-worklist.mjs does exactly that, and admitting it as a family handed it all 2553 — 96% of that PR's entire price.
Why the spawn is not a general guard
check-dispatch-gates.mjs's header already records this verdict at length: it exists as a separate file, spawning rather than importing, because "the derivation resolves a check family to its script file and then scans THAT FILE's source for the path literals it operates on", and a directly-wired gate "would print MATCHED for every card under them — a smaller fabrication than the fixture one, of the same kind."
That guard protects exactly one caller — the one that remembered. It is a convention held in one file's prose, not a property of the module, so the next gate that reaches for discoverFamilies or hintCovers as a library gets the fabrication with no warning and every gate green.
PR #11554 closes the live instance narrowly and by measurement, not generally: a --self-test family follows no import, because that invocation runs the script's self-test rather than its work. A check- gate importing the same module is untouched by that rule.
Not asserted
No claim about which remedy is right. Three shapes, in increasing width:
give the tool's module-scope join bases and tier globs a spelling that does not enter its own hint set — the DEFAULT_BASE_REF idiom already in that file, which avoids exactly this for its own constant;
teach the follow to refuse a module whose literals are join bases rather than a population, which would need its own measurement and a way to tell the two apart.
The second is the one that composes with #11511 and #11510, which want the same module shape for the same reason.
Related
#11404 / PR #11554 (where this was measured, and which closes the live instance) · #11511 (the mirror case: a module that IS a gate file, so the follow refuses it and the honest half is lost) · #11510 · #8162 (check-dispatch-gates.mjs's spawn verdict) · #11190 / PR #11512 (the follow this rides on)
Concentrated triage batch: finding → pm:queue, Task (domain:devx stands) — latent but cheap to close: dispatch-gates.mjs is spawn-reached, not imported, so the "never follow a gate file" rule does not shield it, and its module body yields 9 watch hints covering 2553 files for any future gate that imports it. Fix: make it structurally non-followable (explicit exclusion in discoverFamilies, or move the path strings out of module-body reach per the discoverer's own conventions); self-test pins that importing it fabricates zero pairs.
Clause ②: falsify, don't build on, this seat's assumptions.
Released from a serial hold. This card sat behind scripts/pm/dispatch-gates.mjs until PR #12324 merged (10bd486d62).
Premise re-verified on current origin/main — the mechanism, which is what the card actually claims:
scripts/pm/check-dispatch-gates.mjs:142
const result = spawnSync(process.execPath, [join(ROOT, TOOL), '--self-test'], …)
— imports only node builtins; still reaches the tool by SPAWN, never by import
scripts/pm/bare-root-worklist.mjs:72
} from './dispatch-gates.mjs';
— the live inheritance path is intact
So dispatch-gates.mjs is still not a discovered gate FILE, discoverFamilies' "never follow a module that is itself a gate file" rule still does not protect it, and a real consumer still imports it. The mechanism holds.
⚠️The card's absolute numbers are stale and must be restated, not quoted. It measured 2553 of 6465 tracked files; the tree is now at 6840. Every term has to be re-derived together on one named tree — ⛔ never a denominator refreshed alone.
⭐ And take the right function. This lane just made the opposite mistake twice in one shift: #12300 added if (globInNonFinalSegment(hint)) return triggerCovers(hint, inputPath); at hintCovers:1523, so a hint whose glob sits in a non-final segment never reaches collapseHint at all. Of this card's nine hints, packages/spec/src/** has its glob in the final segment and the rest carry no glob — so the branch probably does not move them, but "probably" is not a measurement. Drive hintCovers, not collapseHint.
Corroborating datum from PR #12324's both-ways derivation, taken independently of this card: that file's own watch-hint set measured 9 before and 9 after, added [], removed [] — matching the card's nine.
Serial constraint: scripts/pm/dispatch-gates.mjs is single-writer for this claim. #12074 · #12046 · #12173 · #12299 all claim the same file and are held behind this card.
{
"issue": 11556,
"status": "done",
"branch": "claude/issue-11556-followable-non-gate-module",
"pr": "https://github.com/objectstack-ai/objectstack/pull/12346",
"premise_still_valid": true,
"summary": "Mechanism re-verified on my own base c48d46d70a: check-dispatch-gates.mjs:142 still reaches the tool by spawnSync, bare-root-worklist.mjs:72 still statically imports it, and no discovered family's files include the tool — so it is still a followable non-gate module and the inheritance path is live. Numbers restated, never quoted: 9 module-body literals covering 2660 of 6840 tracked files (card said 2553 of 6465). Chose shape 3 done by DECLARATION rather than heuristic: the module now carries a marker ('dispatch-gates: inherited-population PATH ... -- REASON') naming the one population a follower inherits, read fresh on every run by hintsOfModule, in the idiom of the two markers already in this file. It is narrowing-only and enforced: a declared path the module does not spell is REFUSED with a throw, so a declaration can remove leads but never invent one. Rejected shape 1 (respell as unslashed halves) because it protects only the literals someone remembered to respell — the same failure one level down — and would have to mangle MANDATORY_TIER_GLOBS/SUSPECT_TIER_GLOBS, a machine-readable copy of a maintainer ruling. Shape 2 (extract a module) is a file-surface change and was NOT built, per zone 1a; #11511/#11510 remain untouched. Result: a gate importing the tool inherits 1 literal / 28 files instead of 9 / 2660. Zero coverage cut — the .github/workflows population the tool really readdirs is pinned as still fully reachable. One file changed, the declared surface. Two operational notes for the PM, neither a repo defect: (1) the additive POST .../labels endpoint is NOT reachable from this dev seat — raw api.github.com returns 'GitHub access is not enabled for this session' and there is no gh CLI — so skip-changeset went on by the declared fallback (read, union, whole-set write) and is confirmed by read-back; (2) GitHub's body sanitizer ate the angle-bracket placeholders out of the PR body's code fence on creation, and the body was re-written without them.",
"tests": "All at final commit 2d5d0fc300 (merged origin/main cf99875ea8 after a STALE TREE warning; re-derived after). Exit codes captured before any pipe, verdicts quoted from each gate's own line. Union derived with 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack' (exit 0, no STALE TREE), 11 matched families, all run: check:agent-test-spelling EXIT=0 · check:bash32-floor EXIT=0 · check:cli-command-ids EXIT=0 ('276 command-id literal(s) across 99 file(s) ... all resolve') · check:cross-package-test-inputs EXIT=0 ('OK: 17 package(s) read outside themselves, all declared') · check:entry-guard EXIT=0 · check:parse-guard EXIT=0 · check:pm-dispatch-gates EXIT=0 ('dispatch-gates self-test: 664 cases pass.', 642 on base) · check:pnpm-filter-targets EXIT=0 · scripts/check-ci-filter-parity EXIT=0 ('OK: all 102 declared cross-package glob(s) ... covered') · scripts/check-cross-package-test-inputs EXIT=0 · scripts/check-self-test-wired EXIT=0. Plus check:nul-bytes EXIT=0 (6834 files, no raw control bytes) and a control-byte self-scan of the diff (grep exit 1, no matches). Repo-wide 'eslint . --no-inline-config' EXIT=0, 83s under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, waited 0s) — a full run, NOT a narrowed one. bare-root-worklist --self-test EXIT=0, output byte-identical to base: '46 live row(s), 39 unreachable as spelled, 39 recorded verdict(s) — none stale, none missing'. NOT MEASURED: check-ci-filter-parity's first attempt printed 'PREREQUISITE NOT MET — the dependency yaml is not installed' in the fresh worktree; the EXIT=0 above is the real run after pnpm install. BOTH-WAYS DERIVATION (this file judges its own PR): base tool from origin/main cf99875ea8 and head tool run over identical 10 input paths in the same tree — plain, --residue and --tier all BYTE-IDENTICAL (25130/49355/1764 bytes). Census identical both ways: 6841 tracked, 173 families, 70013 (gate,file) pairs, 350 inherited hints tree-wide; this file's own watch-hint set 9 before and 9 after, added [] removed []. Driven through hintCovers, not collapseHint (#12300's globInNonFinalSegment short-circuit); measured that none of the nine hints carries a glob in a non-final segment. Live-inheritor sweep found bare-root-worklist.mjs as the only static importer, with a positive control (same search shape returns 10+ hits for js-comment-mask.mjs). ABLATION, two legs, no build/dist leg needed (the tool is source-resolved and run directly by node): (A) deleted the live marker line — mutation confirmed ON DISK by anchored count (live-marker lines 1 to 0, file hash changed), gate EXIT=1 with 7 of 664 named cases failing, the case names printing the restored fabrication verbatim ('inherits 9 of those 9 literal(s)', 'price of that import drops from 2660 tracked files to 2660'); (B) widened the declaration with packages/objectql/src — confirmed on disk (mutated-marker lines 0 to 1, live-marker 1 to 0), gate EXIT=1 with 'declares 1 path(s) this module does not spell: packages/objectql/src — the declaration may only NARROW what a caller inherits, never invent it'. Both legs restored under trap ... EXIT INT TERM; restore proven byte-identical with git hash-object (97e68e68d1c9208f4ccb42c182a9490b1e46c0cc before and after), working tree clean. A FIRST attempt at leg B was refused by its own anchor assertion (the string occurs twice: live marker and docblock example) and never landed on disk — that run measured nothing and is not counted; the second attempt used a line-anchored pattern. Changeset: none, and the reasoning rather than an assumption — scripts/** is repo-internal PM tooling, in no package's published files list, and the diff changes no package runtime behaviour, exports or docs, so there is no user-visible change for a release note; skip-changeset applied and read back on PR #12346 (labels now size/m, skip-changeset).",
"open_questions": [],
"out_of_scope_findings": []
}
(Re-post of the report above — identical JSON. That comment's HTML-comment marker was eaten by GitHub's body sanitizer on write, confirmed by read-back, so the marker is spelled as literal text here. No edit-comment tool is reachable from this seat; this is the scannable copy.)
{
"issue": 11556,
"status": "done",
"branch": "claude/issue-11556-followable-non-gate-module",
"pr": "https://github.com/objectstack-ai/objectstack/pull/12346",
"premise_still_valid": true,
"summary": "Mechanism re-verified on my own base c48d46d70a: check-dispatch-gates.mjs:142 still reaches the tool by spawnSync, bare-root-worklist.mjs:72 still statically imports it, and no discovered family's files include the tool — so it is still a followable non-gate module and the inheritance path is live. Numbers restated, never quoted: 9 module-body literals covering 2660 of 6840 tracked files (card said 2553 of 6465). Chose shape 3 done by DECLARATION rather than heuristic: the module now carries a marker ('dispatch-gates: inherited-population PATH ... -- REASON') naming the one population a follower inherits, read fresh on every run by hintsOfModule, in the idiom of the two markers already in this file. It is narrowing-only and enforced: a declared path the module does not spell is REFUSED with a throw, so a declaration can remove leads but never invent one. Rejected shape 1 (respell as unslashed halves) because it protects only the literals someone remembered to respell — the same failure one level down — and would have to mangle MANDATORY_TIER_GLOBS/SUSPECT_TIER_GLOBS, a machine-readable copy of a maintainer ruling. Shape 2 (extract a module) is a file-surface change and was NOT built, per zone 1a; #11511/#11510 remain untouched. Result: a gate importing the tool inherits 1 literal / 28 files instead of 9 / 2660. Zero coverage cut — the .github/workflows population the tool really readdirs is pinned as still fully reachable. One file changed, the declared surface. Two operational notes for the PM, neither a repo defect: (1) the additive POST .../labels endpoint is NOT reachable from this dev seat — raw api.github.com returns 'GitHub access is not enabled for this session' and there is no gh CLI — so skip-changeset went on by the declared fallback (read, union, whole-set write) and is confirmed by read-back; (2) GitHub's body sanitizer ate the angle-bracket placeholders out of the PR body's code fence on creation, and the body was re-written without them.",
"tests": "All at final commit 2d5d0fc300 (merged origin/main cf99875ea8 after a STALE TREE warning; re-derived after). Exit codes captured before any pipe, verdicts quoted from each gate's own line. Union derived with 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack' (exit 0, no STALE TREE), 11 matched families, all run: check:agent-test-spelling EXIT=0 · check:bash32-floor EXIT=0 · check:cli-command-ids EXIT=0 ('276 command-id literal(s) across 99 file(s) ... all resolve') · check:cross-package-test-inputs EXIT=0 ('OK: 17 package(s) read outside themselves, all declared') · check:entry-guard EXIT=0 · check:parse-guard EXIT=0 · check:pm-dispatch-gates EXIT=0 ('dispatch-gates self-test: 664 cases pass.', 642 on base) · check:pnpm-filter-targets EXIT=0 · scripts/check-ci-filter-parity EXIT=0 ('OK: all 102 declared cross-package glob(s) ... covered') · scripts/check-cross-package-test-inputs EXIT=0 · scripts/check-self-test-wired EXIT=0. Plus check:nul-bytes EXIT=0 (6834 files, no raw control bytes) and a control-byte self-scan of the diff (grep exit 1, no matches). Repo-wide 'eslint . --no-inline-config' EXIT=0, 83s under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, waited 0s) — a full run, NOT a narrowed one. bare-root-worklist --self-test EXIT=0, output byte-identical to base: '46 live row(s), 39 unreachable as spelled, 39 recorded verdict(s) — none stale, none missing'. NOT MEASURED: check-ci-filter-parity's first attempt printed 'PREREQUISITE NOT MET — the dependency yaml is not installed' in the fresh worktree; the EXIT=0 above is the real run after pnpm install. BOTH-WAYS DERIVATION (this file judges its own PR): base tool from origin/main cf99875ea8 and head tool run over identical 10 input paths in the same tree — plain, --residue and --tier all BYTE-IDENTICAL (25130/49355/1764 bytes). Census identical both ways: 6841 tracked, 173 families, 70013 (gate,file) pairs, 350 inherited hints tree-wide; this file's own watch-hint set 9 before and 9 after, added [] removed []. Driven through hintCovers, not collapseHint (#12300's globInNonFinalSegment short-circuit); measured that none of the nine hints carries a glob in a non-final segment. Live-inheritor sweep found bare-root-worklist.mjs as the only static importer, with a positive control (same search shape returns 10+ hits for js-comment-mask.mjs). ABLATION, two legs, no build/dist leg needed (the tool is source-resolved and run directly by node): (A) deleted the live marker line — mutation confirmed ON DISK by anchored count (live-marker lines 1 to 0, file hash changed), gate EXIT=1 with 7 of 664 named cases failing, the case names printing the restored fabrication verbatim ('inherits 9 of those 9 literal(s)', 'price of that import drops from 2660 tracked files to 2660'); (B) widened the declaration with packages/objectql/src — confirmed on disk (mutated-marker lines 0 to 1, live-marker 1 to 0), gate EXIT=1 with 'declares 1 path(s) this module does not spell: packages/objectql/src — the declaration may only NARROW what a caller inherits, never invent it'. Both legs restored under trap ... EXIT INT TERM; restore proven byte-identical with git hash-object (97e68e68d1c9208f4ccb42c182a9490b1e46c0cc before and after), working tree clean. A FIRST attempt at leg B was refused by its own anchor assertion (the string occurs twice: live marker and docblock example) and never landed on disk — that run measured nothing and is not counted; the second attempt used a line-anchored pattern. Changeset: none, and the reasoning rather than an assumption — scripts/** is repo-internal PM tooling, in no package's published files list, and the diff changes no package runtime behaviour, exports or docs, so there is no user-visible change for a release note; skip-changeset applied and read back on PR #12346 (labels now size/m, skip-changeset).",
"open_questions": [],
"out_of_scope_findings": []
}
Activity
claude commentedon Aug 25, 2026
Concentrated triage batch:
finding→pm:queue, Task (domain:devxstands) — latent but cheap to close:dispatch-gates.mjsis spawn-reached, not imported, so the "never follow a gate file" rule does not shield it, and its module body yields 9 watch hints covering 2553 files for any future gate that imports it. Fix: make it structurally non-followable (explicit exclusion indiscoverFamilies, or move the path strings out of module-body reach per the discoverer's own conventions); self-test pins that importing it fabricates zero pairs.Generated by Claude Code
yinlianghui commentedon Aug 25, 2026
Claim —
domain:devx @ objectstackseat (#6023), sessionsession_01UjM2ia8Av1v5NqfqQEQmC6.claude/issue-11556-followable-non-gate-module../objectstack-11556(dedicated)Released from a serial hold. This card sat behind
scripts/pm/dispatch-gates.mjsuntil PR #12324 merged (10bd486d62).Premise re-verified on current
origin/main— the mechanism, which is what the card actually claims:So
dispatch-gates.mjsis still not a discovered gate FILE,discoverFamilies' "never follow a module that is itself a gate file" rule still does not protect it, and a real consumer still imports it. The mechanism holds.⭐ And take the right function. This lane just made the opposite mistake twice in one shift: #12300 added
if (globInNonFinalSegment(hint)) return triggerCovers(hint, inputPath);athintCovers:1523, so a hint whose glob sits in a non-final segment never reachescollapseHintat all. Of this card's nine hints,packages/spec/src/**has its glob in the final segment and the rest carry no glob — so the branch probably does not move them, but "probably" is not a measurement. DrivehintCovers, notcollapseHint.Corroborating datum from PR #12324's both-ways derivation, taken independently of this card: that file's own watch-hint set measured 9 before and 9 after,
added [],removed []— matching the card's nine.Serial constraint:
scripts/pm/dispatch-gates.mjsis single-writer for this claim. #12074 · #12046 · #12173 · #12299 all claim the same file and are held behind this card.Generated by Claude Code
yinlianghui commentedon Aug 25, 2026
{ "issue": 11556, "status": "done", "branch": "claude/issue-11556-followable-non-gate-module", "pr": "https://github.com/objectstack-ai/objectstack/pull/12346", "premise_still_valid": true, "summary": "Mechanism re-verified on my own base c48d46d70a: check-dispatch-gates.mjs:142 still reaches the tool by spawnSync, bare-root-worklist.mjs:72 still statically imports it, and no discovered family's files include the tool — so it is still a followable non-gate module and the inheritance path is live. Numbers restated, never quoted: 9 module-body literals covering 2660 of 6840 tracked files (card said 2553 of 6465). Chose shape 3 done by DECLARATION rather than heuristic: the module now carries a marker ('dispatch-gates: inherited-population PATH ... -- REASON') naming the one population a follower inherits, read fresh on every run by hintsOfModule, in the idiom of the two markers already in this file. It is narrowing-only and enforced: a declared path the module does not spell is REFUSED with a throw, so a declaration can remove leads but never invent one. Rejected shape 1 (respell as unslashed halves) because it protects only the literals someone remembered to respell — the same failure one level down — and would have to mangle MANDATORY_TIER_GLOBS/SUSPECT_TIER_GLOBS, a machine-readable copy of a maintainer ruling. Shape 2 (extract a module) is a file-surface change and was NOT built, per zone 1a; #11511/#11510 remain untouched. Result: a gate importing the tool inherits 1 literal / 28 files instead of 9 / 2660. Zero coverage cut — the .github/workflows population the tool really readdirs is pinned as still fully reachable. One file changed, the declared surface. Two operational notes for the PM, neither a repo defect: (1) the additive POST .../labels endpoint is NOT reachable from this dev seat — raw api.github.com returns 'GitHub access is not enabled for this session' and there is no gh CLI — so skip-changeset went on by the declared fallback (read, union, whole-set write) and is confirmed by read-back; (2) GitHub's body sanitizer ate the angle-bracket placeholders out of the PR body's code fence on creation, and the body was re-written without them.", "tests": "All at final commit 2d5d0fc300 (merged origin/main cf99875ea8 after a STALE TREE warning; re-derived after). Exit codes captured before any pipe, verdicts quoted from each gate's own line. Union derived with 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack' (exit 0, no STALE TREE), 11 matched families, all run: check:agent-test-spelling EXIT=0 · check:bash32-floor EXIT=0 · check:cli-command-ids EXIT=0 ('276 command-id literal(s) across 99 file(s) ... all resolve') · check:cross-package-test-inputs EXIT=0 ('OK: 17 package(s) read outside themselves, all declared') · check:entry-guard EXIT=0 · check:parse-guard EXIT=0 · check:pm-dispatch-gates EXIT=0 ('dispatch-gates self-test: 664 cases pass.', 642 on base) · check:pnpm-filter-targets EXIT=0 · scripts/check-ci-filter-parity EXIT=0 ('OK: all 102 declared cross-package glob(s) ... covered') · scripts/check-cross-package-test-inputs EXIT=0 · scripts/check-self-test-wired EXIT=0. Plus check:nul-bytes EXIT=0 (6834 files, no raw control bytes) and a control-byte self-scan of the diff (grep exit 1, no matches). Repo-wide 'eslint . --no-inline-config' EXIT=0, 83s under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, waited 0s) — a full run, NOT a narrowed one. bare-root-worklist --self-test EXIT=0, output byte-identical to base: '46 live row(s), 39 unreachable as spelled, 39 recorded verdict(s) — none stale, none missing'. NOT MEASURED: check-ci-filter-parity's first attempt printed 'PREREQUISITE NOT MET — the dependency yaml is not installed' in the fresh worktree; the EXIT=0 above is the real run after pnpm install. BOTH-WAYS DERIVATION (this file judges its own PR): base tool from origin/main cf99875ea8 and head tool run over identical 10 input paths in the same tree — plain, --residue and --tier all BYTE-IDENTICAL (25130/49355/1764 bytes). Census identical both ways: 6841 tracked, 173 families, 70013 (gate,file) pairs, 350 inherited hints tree-wide; this file's own watch-hint set 9 before and 9 after, added [] removed []. Driven through hintCovers, not collapseHint (#12300's globInNonFinalSegment short-circuit); measured that none of the nine hints carries a glob in a non-final segment. Live-inheritor sweep found bare-root-worklist.mjs as the only static importer, with a positive control (same search shape returns 10+ hits for js-comment-mask.mjs). ABLATION, two legs, no build/dist leg needed (the tool is source-resolved and run directly by node): (A) deleted the live marker line — mutation confirmed ON DISK by anchored count (live-marker lines 1 to 0, file hash changed), gate EXIT=1 with 7 of 664 named cases failing, the case names printing the restored fabrication verbatim ('inherits 9 of those 9 literal(s)', 'price of that import drops from 2660 tracked files to 2660'); (B) widened the declaration with packages/objectql/src — confirmed on disk (mutated-marker lines 0 to 1, live-marker 1 to 0), gate EXIT=1 with 'declares 1 path(s) this module does not spell: packages/objectql/src — the declaration may only NARROW what a caller inherits, never invent it'. Both legs restored under trap ... EXIT INT TERM; restore proven byte-identical with git hash-object (97e68e68d1c9208f4ccb42c182a9490b1e46c0cc before and after), working tree clean. A FIRST attempt at leg B was refused by its own anchor assertion (the string occurs twice: live marker and docblock example) and never landed on disk — that run measured nothing and is not counted; the second attempt used a line-anchored pattern. Changeset: none, and the reasoning rather than an assumption — scripts/** is repo-internal PM tooling, in no package's published files list, and the diff changes no package runtime behaviour, exports or docs, so there is no user-visible change for a release note; skip-changeset applied and read back on PR #12346 (labels now size/m, skip-changeset).", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
yinlianghui commentedon Aug 25, 2026
os-dev-report
(Re-post of the report above — identical JSON. That comment's HTML-comment marker was eaten by GitHub's body sanitizer on write, confirmed by read-back, so the marker is spelled as literal text here. No edit-comment tool is reachable from this seat; this is the scannable copy.)
{ "issue": 11556, "status": "done", "branch": "claude/issue-11556-followable-non-gate-module", "pr": "https://github.com/objectstack-ai/objectstack/pull/12346", "premise_still_valid": true, "summary": "Mechanism re-verified on my own base c48d46d70a: check-dispatch-gates.mjs:142 still reaches the tool by spawnSync, bare-root-worklist.mjs:72 still statically imports it, and no discovered family's files include the tool — so it is still a followable non-gate module and the inheritance path is live. Numbers restated, never quoted: 9 module-body literals covering 2660 of 6840 tracked files (card said 2553 of 6465). Chose shape 3 done by DECLARATION rather than heuristic: the module now carries a marker ('dispatch-gates: inherited-population PATH ... -- REASON') naming the one population a follower inherits, read fresh on every run by hintsOfModule, in the idiom of the two markers already in this file. It is narrowing-only and enforced: a declared path the module does not spell is REFUSED with a throw, so a declaration can remove leads but never invent one. Rejected shape 1 (respell as unslashed halves) because it protects only the literals someone remembered to respell — the same failure one level down — and would have to mangle MANDATORY_TIER_GLOBS/SUSPECT_TIER_GLOBS, a machine-readable copy of a maintainer ruling. Shape 2 (extract a module) is a file-surface change and was NOT built, per zone 1a; #11511/#11510 remain untouched. Result: a gate importing the tool inherits 1 literal / 28 files instead of 9 / 2660. Zero coverage cut — the .github/workflows population the tool really readdirs is pinned as still fully reachable. One file changed, the declared surface. Two operational notes for the PM, neither a repo defect: (1) the additive POST .../labels endpoint is NOT reachable from this dev seat — raw api.github.com returns 'GitHub access is not enabled for this session' and there is no gh CLI — so skip-changeset went on by the declared fallback (read, union, whole-set write) and is confirmed by read-back; (2) GitHub's body sanitizer ate the angle-bracket placeholders out of the PR body's code fence on creation, and the body was re-written without them.", "tests": "All at final commit 2d5d0fc300 (merged origin/main cf99875ea8 after a STALE TREE warning; re-derived after). Exit codes captured before any pipe, verdicts quoted from each gate's own line. Union derived with 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack' (exit 0, no STALE TREE), 11 matched families, all run: check:agent-test-spelling EXIT=0 · check:bash32-floor EXIT=0 · check:cli-command-ids EXIT=0 ('276 command-id literal(s) across 99 file(s) ... all resolve') · check:cross-package-test-inputs EXIT=0 ('OK: 17 package(s) read outside themselves, all declared') · check:entry-guard EXIT=0 · check:parse-guard EXIT=0 · check:pm-dispatch-gates EXIT=0 ('dispatch-gates self-test: 664 cases pass.', 642 on base) · check:pnpm-filter-targets EXIT=0 · scripts/check-ci-filter-parity EXIT=0 ('OK: all 102 declared cross-package glob(s) ... covered') · scripts/check-cross-package-test-inputs EXIT=0 · scripts/check-self-test-wired EXIT=0. Plus check:nul-bytes EXIT=0 (6834 files, no raw control bytes) and a control-byte self-scan of the diff (grep exit 1, no matches). Repo-wide 'eslint . --no-inline-config' EXIT=0, 83s under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, waited 0s) — a full run, NOT a narrowed one. bare-root-worklist --self-test EXIT=0, output byte-identical to base: '46 live row(s), 39 unreachable as spelled, 39 recorded verdict(s) — none stale, none missing'. NOT MEASURED: check-ci-filter-parity's first attempt printed 'PREREQUISITE NOT MET — the dependency yaml is not installed' in the fresh worktree; the EXIT=0 above is the real run after pnpm install. BOTH-WAYS DERIVATION (this file judges its own PR): base tool from origin/main cf99875ea8 and head tool run over identical 10 input paths in the same tree — plain, --residue and --tier all BYTE-IDENTICAL (25130/49355/1764 bytes). Census identical both ways: 6841 tracked, 173 families, 70013 (gate,file) pairs, 350 inherited hints tree-wide; this file's own watch-hint set 9 before and 9 after, added [] removed []. Driven through hintCovers, not collapseHint (#12300's globInNonFinalSegment short-circuit); measured that none of the nine hints carries a glob in a non-final segment. Live-inheritor sweep found bare-root-worklist.mjs as the only static importer, with a positive control (same search shape returns 10+ hits for js-comment-mask.mjs). ABLATION, two legs, no build/dist leg needed (the tool is source-resolved and run directly by node): (A) deleted the live marker line — mutation confirmed ON DISK by anchored count (live-marker lines 1 to 0, file hash changed), gate EXIT=1 with 7 of 664 named cases failing, the case names printing the restored fabrication verbatim ('inherits 9 of those 9 literal(s)', 'price of that import drops from 2660 tracked files to 2660'); (B) widened the declaration with packages/objectql/src — confirmed on disk (mutated-marker lines 0 to 1, live-marker 1 to 0), gate EXIT=1 with 'declares 1 path(s) this module does not spell: packages/objectql/src — the declaration may only NARROW what a caller inherits, never invent it'. Both legs restored under trap ... EXIT INT TERM; restore proven byte-identical with git hash-object (97e68e68d1c9208f4ccb42c182a9490b1e46c0cc before and after), working tree clean. A FIRST attempt at leg B was refused by its own anchor assertion (the string occurs twice: live marker and docblock example) and never landed on disk — that run measured nothing and is not counted; the second attempt used a line-anchored pattern. Changeset: none, and the reasoning rather than an assumption — scripts/** is repo-internal PM tooling, in no package's published files list, and the diff changes no package runtime behaviour, exports or docs, so there is no user-visible change for a release note; skip-changeset applied and read back on PR #12346 (labels now size/m, skip-changeset).", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
fix(dispatch-gates): stop inheriting the CLI package as a population …
fix(dispatch-gates): stop inheriting the CLI package as a population …
feat(pm): gate the clause-② carrier strip on the served tier the verd…
fix(pm): decide an inherited population per CALLER, off what the impo…