Skip to content

feat(pm): wide-population, a third dispatch-gates derivation channel - #15737

Merged
baozhoutao merged 3 commits into
mainfrom
claude/issue-15341-wide-population-channel
Sep 5, 2026
Merged

feat(pm): wide-population, a third dispatch-gates derivation channel#15737
baozhoutao merged 3 commits into
mainfrom
claude/issue-15341-wide-population-channel

Conversation

@claude

@claude claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #15341

Implements the maintainer ruling recorded in comment 5548765257 (decision batch #43, verbatim reply 「同意」): option D, a third derivation channel. PR #15466 landed the Part of half (the families neither map refused); this lands the half that needed the ruling.

dispatch-gates.mjs gains a third derivation channel, wide-population — a gate declares "CI runs me over a population too wide to place", which lists it in the residue's declared column and keeps it OUT of the matched column; the eleven REFUSE-WIDE / REFUSE-UNSPELLABLE families move onto it; bare-root-worklist.mjs's rows are not deleted.

The channel's contract

Marker, spelled as the exact sibling of the two that already exist, in both comment forms:

// dispatch-gates: wide-population -- REASON
#  dispatch-gates: wide-population -- REASON      (shell gates)
  • Declared, not undetermined. A declaring family leaves the undetermined bucket for a verdict of its own, wide-population, and is rendered under its own heading — Declared WIDE population — with the gate's reason. That is the residue's declared column the ruling names.
  • Out of the matched column, and out of --commands. No card's paths place it, and its command is deliberately not in the runnable union. This is the one difference from whole-tree-population beside it: a whole-tree gate is owed by every card so its command sits inside every card's total; a wide-population gate is owed by CI and by no card in particular, and pasting it into every harvest would be the fabricated lead bare-root-worklist.mjs refused in the first place. The --commands / --json stderr accounting states the omission out loud, and --json carries a widePopulation key beside alwaysRunsPopulation.
  • The reason is required, and it has to do more work here than on either sibling. It must name the population in words — which root or roots the gate walks, and why no subtree glob places it — because that sentence is the entire content of the channel. A marker with no reason does not parse as a declaration.
  • A gate declares exactly ONE population shape. widePopulationRefusal refuses the marker paired with no-path-population, paired with whole-tree-population, or sitting above a scanned path population (it names the literals so a reader can decide which half is wrong). wholeTreePopulationRefusal states the mirror, so whichever channel a reader arrives through, the pair is refused rather than resolved by a coin toss.

One boundary that is a judgement, stated rather than buried

The declaration is a claim about the gate's population. It therefore does not suppress coveringKey's identity key: a card that edits the gate's own script still matches it and still gets its command. coveringKey's own docblock calls the identity key "an identity claim about a single FILE", not a population claim; the ruling's "keeps it OUT of the matched column" is about the roots the gate walks, and the gate you are editing is the one gate you certainly owe. Suppressing it would make a channel added to ADD information subtract some, silently, on the one card class where the derivation is exactly right. This is why placeFamily consults this declaration AFTER the classifier while the whole-tree one is consulted BEFORE it — the asymmetry is the design, it is documented at the seam, and both directions are pinned (including a case asserting the whole-tree channel still DOES suppress the identity match, so neither can be tidied into the other).

The declarations — ten, not eleven

Re-derived on today's origin/main rather than carried from report 5543976876. Ten of the eleven withdrawn families are still undetermined and now declare. The eleventh, scripts/check-declaration-mirrors.mjs (two invocations), has since declared a real population (scripts/**/*.d.mts, scripts/**/*.mjs) and is silent, not undetermined — it no longer needs the marker, and its REFUSE-UNSPELLABLE row is untouched and uncontradicted (neither hint reaches an arbitrary file at the top of scripts).

Each reason names the roots walked, the recorded share, and the verdict it agrees with:

gate population it walks recorded verdict
check:init-service-contract walk(join(ROOT, 'packages')), non-test .ts — 2182 of 5837 (37.4%, base 2aa8456) REFUSE-WIDE (census)
check:live-db-isolation ROOTS = packages, apps, examples; every .ts/.mts non-.d.ts — 5269 of 5837 (90.3%) REFUSE-WIDE (census)
check:meta-type-normalized SCAN_DIRS = packages/rest/src, non-test sources — 21 of 154 (14%): the file-KIND filter is what cannot be spelled, not the subtree REFUSE-UNSPELLABLE
check:optional-error-sink SCAN_ROOTS = packages, non-test .ts — 1898 of 4903 (39%) REFUSE-WIDE
check:resume-authority-declared DEFAULT_SCAN_ROOTS = packages, examples — 39% and 68%, refused together REFUSE-WIDE (both halves)
check:runner-env-posture SCANNED_ROOTS = packages, apps, examples; non-test source beneath a src segment — 35%, 62%, and 0 of 35 under apps REFUSE-UNSPELLABLE (all three)
check:settings-bind-window walk(join(ROOT, 'packages')), non-test .ts — 2182 of 5837 (37.4%) REFUSE-WIDE (census)
check:startup-registry-verdict scan root join(ROOT, 'packages'), non-test .ts — 2182 of 5837 (37.4%) REFUSE-WIDE (census)
check:verify-stand-in SCAN_ROOTS = packages, examples — 39% and 68%, refused together REFUSE-WIDE (both halves)
check:wildcard-fallthrough walk(join(ROOT, 'packages')), non-test .ts — 2182 of 5837 (37.4%) REFUSE-WIDE (census)

Every share is the one recorded in scripts/pm/bare-root-worklist.mjs at the base that row names, cited as such — not a fresh measurement wearing that row's digits.

bare-root-worklist.mjs: the marker accepted, no row deleted

The contradiction check is now the pure contradictedRows(rows, triage), and a covered row whose gate carries the marker is not contradicted: the marker agrees with the recorded refusal instead of overriding it, which is the deliberate-declaration form the message already permitted — at last without the cost that resolution used to carry (withdrawing the verdict and losing the measured reason). No row is deleted, edited or re-pointed.

Both directions are pinned on fixtures, and the fixtures are the point: the live direction is vacuous on this tree (9 rows' gates carry the marker, none of them covered), so a live-only pin would be an assertion over an empty set that reads exactly like a pass. Beside them, a control names the handoff: the shape this file excuses — a marker sitting above a covering hint — is REFUSED by widePopulationRefusal in the file that owns markers, so no configuration is excused by both. The self-test verdict line now carries the count.

Measurements

Every exit code captured before any pipe (cmd > log 2>&1; EXIT=$?); every verdict quoted from the gate's own stdout.

Residue, both legs on one tree (--residue README.md, probe path touches none of the ten):

tree undetermined declared-wide
merge base 8e8860ed8 41 0
branch at 2bc5ece11 31 10
final head 44e6f63bb, channel ablated 40 0
final head 44e6f63bb 30 10

41 is today's re-measure of the card's stated 43 — the tree grew (259 families discovered, not 254), so the card's number is stale rather than wrong. Target was ≤ 32; both paired readings are ten below their own before-leg, and the last two are the same tree with only this channel differing. The final-head pair moved to 40/30 because origin/main landed work between the two measurements, which is why both are quoted with the commit they were taken at.

Behavioural proof, matched column: node scripts/pm/dispatch-gates.mjs --commands packages/rest/src/rest-server.ts — exit 0, 39 commands, and none of the ten is among them; stderr states + 10 famil(ies) DECLARE a population too wide to place and are NOT above. At base those ten had hints: [] and no marker, so the zero is structural as well as measured. The identity direction is proved by the same tool on this card's own change set: --changed --commands emits all ten, because the diff edits their scripts.

Ablation (trap-guarded, absolute paths, on-disk proof in both directions). No build leg applies and none is claimed: node scripts/pm/dispatch-gates.mjs executes the source file directly and the self-test lives in that same file — no package exports resolution, no dist/.

Run twice: the full instrument at 2bc5ece11, and the residue legs again at the final head 44e6f63bb so the numbers quoted above belong to the tree that was pushed.

at 2bc5ece11 (full)                       at 44e6f63bb (residue legs)
HEAD_BLOB=cf58c06142574ca2d0eea479b9722f891085c877          (same blob both runs)
BEFORE_HASH=cf58c06142574ca2d0eea479b9722f891085c877        (aborts unless these match)
MARKER_LINES_BEFORE=1 -> MARKER_LINES_AFTER=0               (same)
MUTATED_HASH=dd0a6b350f53ccf939274de3c0f53d1c19c0870f       (mutation reached disk)
ABLATED_RESIDUE_EXIT=0  · 41 undetermined · 0 declared-wide | · 40 undetermined · 0 declared-wide
ABLATED_SELFTEST_EXIT=1 · 5 failing cases                   | (self-test leg not repeated)
RESTORED_HASH=cf58c06142574ca2d0eea479b9722f891085c877      (== HEAD blob, both runs)
GIT_DIFF_HEAD_EMPTY=yes · MARKER_LINES_RESTORED=1           (both runs)
RESTORED_RESIDUE_EXIT=0 · 31 undetermined · 10 declared-wide | · 30 undetermined · 10 declared-wide

The five failing cases are exactly this channel's placement pins, three fixture and two live:

✗ DECLARED column: a declaring family is placed as wide-population, not undetermined — it has been READ
✗ MATCHED column: a card under the root it walks does NOT match it — the whole point of the ruling
✗ NOT silent either: a gate that really does read your file must never print as a clearance
✗ no live wide-population family is matched by a card under the roots it walks — it stays in its own declared column
✗ and none of them is left in `undetermined` for a card that touches nothing of theirs — the bucket the ruling moved them OUT of

Gates. The derived family for this diff — node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack, 39 commands — was run in full, plus node scripts/pm/dispatch-gates.mjs --self-test: 40 of 40 exit 0, on the final head 44e6f63bb (git rev-parse --short HEAD at that run), in one locked batch — os-verify-lock slot issue-15341, VERDICT command-exit 0 · held the lock 1085s (18m05s) · waited 45s. The command set was re-derived after merging origin/main and is identical to the pre-merge derivation. Verdict lines:

  • ✓ dispatch-gates self-test: 1478 cases pass. (base was 1445; +33, none weakened, none deleted) — the same line from pnpm check:pm-dispatch-gates.
  • bare-root-worklist --self-test: OK self-test: 54 live row(s), 46 unreachable as spelled, 46 recorded verdict(s) — none stale, none missing, none contradicted (9 row(s) whose gate carries the dispatch-gates wide-population declaration, the deliberate-declaration form this file accepts without withdrawing a verdict; none of them is covered, so none is excused by it today).
  • ✓ check:declared-population-live — 214 of 259 famil(ies) declare a path population, and every one of them reaches this tree's 7600 tracked file(s).
  • ✓ check-watch-hint-literal: 58 declaration(s) across 4 rostered name(s) … no unrostered spelling of the idiom in the tree.
  • check-nul-bytes: OK (scanned 7593 text file(s) … no raw ASCII control bytes).
  • ✓ check-self-test-wired: every one of the 172 script(s) CI runs that ship a --self-test has that self-test run by CI.
  • Each of the ten edited gates' own check:* (self-test leg and production leg): exit 0.

check-declared-population-live.mjs and check-watch-hint-literal.mjs were not edited — rostering the marker required nothing there: it is a comment, not a declaration array.

Governed: node scripts/pm/check-governed-merges.mjs --test over the final twelve-file list — exit 0, governed-surface predicate: 0 of 12 path(s) hit the register (5 surfaces, repo-agnostic). ✅ NOT governed. So this is an ordinary PR, not the governed draft the ruling anticipated: none of the ten gates lives under .claude/**, skills/** or docs/adr/**. It stays draft because every os-dev PR does, and no review is requested on governance grounds.

No changeset: scripts/ publishes nothing from any released package; skip-changeset applied.

NOT MEASURED, by name: no ablation of the bare-root-worklist acceptance was performed (its live direction is vacuous, as stated above — the fixture pins are what carry it); the whole-repo pnpm lint was not run here and is left to CI; nothing in this run exited 3 or hit a PREREQUISITE NOT MET.

🤖 Generated with Claude Code

https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk


Generated by Claude Code

@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 5, 2026
@github-actions github-actions Bot added the size/l label Sep 5, 2026
@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

ACCEPT — PR #15737 (head 44e6f63bb) reviewed against the GitHub three-dot diff (12 files, +615/−20), not the report.

Ruling on the open question (identity-key survival): A, as shipped. The wide-population declaration is a claim about the gate's population; coveringKey's identity key is a claim about one file. A card that edits the gate's own script owes that gate with 100 % precision, and the ruling's "keeps it OUT of the matched column" contrasts with declaring the roots. The asymmetry (placeFamily consults this channel AFTER the classifier, whole-tree BEFORE) is documented at the seam and pinned in both directions, including the control that the whole-tree channel still suppresses the identity match — accepted as the design.

Ten declarations, not eleven: accepted. check-declaration-mirrors.mjs declares scripts/**/*.d.mts + scripts/**/*.mjs on today's main and is silent, so it needs no marker; its REFUSE-UNSPELLABLE row is untouched.

Measured by this seat (branch checked out detached at 44e6f63bb; every EXIT read from the run before any pipe):

  • node scripts/pm/dispatch-gates.mjs --self-test → EXIT=0, ✓ dispatch-gates self-test: 1478 cases pass. (main eca504724: 1445). First attempt crashed in exposedScratchDirs with git check-ignore … is beyond a symbolic link because the probe tree's node_modules was a symlink — a probe artefact, not the PR; re-run with a real directory.
  • node scripts/pm/bare-root-worklist.mjs --self-test → EXIT=0, OK self-test: 54 live row(s), 46 unreachable as spelled, 46 recorded verdict(s) — none stale, none missing, none contradicted (9 row(s) whose gate carries the dispatch-gates wide-population declaration …).
  • --residue README.md: branch → EXIT=0, Declared WIDE population — 10 famil(ies), 30 undetermined; main 1847594de → EXIT=0, Undetermined … 40 famil(ies), no declared-wide block. Delta −10, matches the report.
  • --commands packages/rest/src/rest-server.ts → EXIT=0, 39 commands, 0 of the ten gates among them; stderr + 10 famil(ies) DECLARE a population too wide to place and are NOT above.
  • check-governed-merges.mjs --test <12 paths> → EXIT=0, 0 of 12 path(s) hit the register … ✅ NOT governed.
  • git merge-tree --write-tree origin/main <branch> → EXIT=0 (clean against eca504724).

Serial-file hold: scripts/check-settings-bind-window.mjs is also in PR #15729 (#15614 + #15657), which is armed and in the merge queue. Two live PRs of this lane never share a hot file, so this PR is flipped/armed only after #15729 lands and merge-tree is re-run against that main. Required jobs are watched meanwhile.

NOT MEASURED here: the ten gates' own check:* production legs and the 39-command derived family (the report's locked batch issue-15341, 40 of 40 exit 0, is the record); no pnpm lint.

On landing: #15341 closes; #15468 unblocks.


Generated by Claude Code

@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Flipped ready + auto-merge enabled (05:52Z, method: MERGE) — the serial-file hold cleared when PR #15729 landed as 5b0c77909; git merge-tree --write-tree origin/main <branch> re-run against that main → EXIT=0 (clean). Required jobs on 44e6f63bb: Lint & Repo Gates = success, TypeScript Type Check = success. Watched; on landing #15341 closes, #15468 unblocks.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/l skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants