docs(pm-dispatch): read the verify-lock queue depth before each dispatch and hold at depth ≥ 2 (#14944 Q1 B) - #16271
Conversation
…tch and hold at depth >= 2 The dispatch cap counts cards in flight; the container-wide heavy-verify lock is one unit wide, and the measured exit-99 (NOT MEASURED) rate is a function of arrival queue depth alone: 1% / 23% / 36% / 56% at depth 1 / 2 / 3 / 4. The PM loop now reads `scripts/pm/os-verify-lock.sh --status` before the N-th dispatch and waits while the arrival depth (`queue N:` lines + the dev's own run; holder and parked slots not counted) would reach LOCK_DEPTH_HOLD = 2. The nominal `batch` cap is unchanged; `priority:p0` may still exceed `batch` but does not cross the depth hold. Both places carry the rule (SKILL.md and references/core-rules.md). The four added lines are paid inside the same file by four same-topic merges, so the line ratchet stays at its ceilings. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
|
Skills-seat reading (2026-09-06T14:5xZ), for the devx seat and this PR's dev: this PR and flight A of the skills lane (PR #16339, Generated by Claude Code |
|
PR #16339 (flight A) merged at 2026-09-07T01:18:23Z as Generated by Claude Code |
Part of #14944.
Implements the Q1 B half of the maintainer ruling recorded on the card (comment
5548762263, director seat, 2026-09-05, maintainer 「同意」). The card does not close on this PR — it closes on the one-week--reportre-measure the ruling asks for. The Q3 A half (the dev waiting discipline in.claude/agents/os-dev.md) is thedomain:skillslane's: #16262 remains open and is not touched here.The ruling (quoted)
Depth table the ruling adopted (dev measurement
5547089539, 313 ledger records / 35.1 h): exit-99 (NOT MEASURED) rate 1.0% / 22.6% / 36.1% / 55.6% at arrival queue depth 1 / 2 / 3 / 4.What changes
.claude/skills/pm-dispatch/SKILL.md, 执行座位职责 → 候选与批次, directly under thebatchcap line — four rules:scripts/pm/os-verify-lock.sh --status; when the arrival depth would be ≥LOCK_DEPTH_HOLD(= 2) the dispatch waits.queue N:行数 + 1(待派 dev 的运行算作到达);state:holder 与parked行不计。」 — the number ofqueue N:lines in the--statusoutput, plus one for the run the dev about to be dispatched will bring. Thestate:holder line andparked N:lines are not counted.batch;priority:p0may still exceedbatchbut does not cross the depth hold.The
priority:p0state-table row gains 「深度等待」 among the things queue-jumping does not exempt.references/core-rules.mdcarries both changes in its one-line form (line 11 and line 39), per the skill's own two-place rule.Why the holder is not counted. The threshold is defined on the ledger's
depthcolumn, which is what the depth table was computed over. That column is read byqueue_live | wc -lright after the arriving call mints its own ticket, and a run's ticket is removed at the moment it acquires (rm -f "$TICKET"immediately afterHOLDING=1), so the holder is never inqueue_live.--reportstates the same: "queue depth on arrival (the arriving run INCLUDED — 1 means nobody was ahead)". Counting the holder would shift every reading by one and hold at what the table calls depth 1 (1.0% exit-99). The two readings the PM seat already took under this rule (holder + 1 waiter ⇒ hold at 08:31Z; holder + empty queue ⇒ depth 1 ⇒ dispatch at 08:49Z) agree with this counting.One-liner over
--statusoutput, for the seat (no new flag added to the script —--statusexposes no machine-readable depth, and wideningscripts/pm/**is outside this card's file surface):Live reading while writing this, 2026-09-06T08:57:48Z:
state: holder pid 4035, held 338s — pnpm --filter '@objectstack/client-react...' build·queue: empty⇒ waiters 0, arrival depth 1 (below the hold).Provenance placement.
pnpm check:pm-skill-id-lintrejects any#followed by three or more digits in the skill corpus (maintainer ruling 2026-08-12: a rule's provenance lives in the PR that landed it), so the card number cannot appear in the skill text. The in-text provenance is the depth table itself; this PR is where the card is named.Line ratchet — paid in the same file
All three pm-dispatch files sit at headroom 0. The four added lines are paid by four same-topic merges inside
SKILL.md(no rule removed, no ceiling raised, no cross-file move):Ratchet readings at head
4d3194ba7:SKILL.md is 811 lines (ceiling 811; headroom 0),widest table row is 342 bytes (pin 342; headroom 0);core-rules.md is 150 lines (ceiling 150; headroom 0). Every added or edited prose line is ≤ 120 bytes (max 118 B).Gates — pinned to head
4d3194ba7Derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands(no paths; change set from the merge base8adb9e84a): 16 commands, identical to the path-derived list.--ranreconciliation:16 derived, 16 run, 0 NOT-MEASURED, 0 UNRUN. Exit codes captured by redirect before any pipe.pnpm check:pm-skill-ratchet✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md is 811 lines (ceiling 811; headroom 0).pnpm check:pm-skill-id-lint✓ check-skill-id-lint: 25 file(s) clean (pattern /#[0-9]{3,}/g).pnpm check:pm-governed-prose✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.pnpm check:skill-frame-sync✓ check-skill-frame-sync: 2 copies of the decision frame are structurally isomorphic across 2 filespnpm check:nul-bytes✓ check-nul-bytes --self-test: 75 assertions …pnpm check:agent-test-spelling✓ check-agent-test-spelling: 0 violations — 461 file(s) …pnpm check:doc-authoring✓ doc authoring guard: 46 published skill files clean …pnpm check:watch-hint-literal✓ check-watch-hint-literal: 62 declaration(s) across 4 rostered name(s) …node scripts/check-closing-keyword-parity.mjsnode scripts/check-closing-keyword-parity.mjs --self-test✓ check-closing-keyword-parity --self-test: 24 assertions, 5 mutations …node scripts/check-comment-mask-corpus.mjs✓ comment-mask corpus sweep: 6202 files, 0 disagree, 0 unparseablenode scripts/pm/check-governed-queue-guard.mjs --self-test✓ check-governed-queue-guard self-test: 144 cases passpnpm check:refd-timer-probe✓ check-refd-timer-probe self-test: 11 cases passpnpm check:driver-memory-censuspnpm check:pm-governed-merges✓ check-governed-merges --self-test: 274 assertions …pnpm --filter @objectstack/lint run check:doc-formula-expressions✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 429 files / 1371 TS blocks judged cleanThe last gate first refused with exit 3
PREREQUISITE NOT MET(unbuilt@objectstack/formula/@objectstack/lint— NOT MEASURED, not a red); the prerequisites were built through the shared lock (os-verify-lock: VERDICT command-exit 0 · held the lock 181s · waited 0s, 4 turbo tasks incl.@objectstack/spec) and the gate re-run is the row above.Note from the derivation tool: the worktree is one commit behind
origin/main(6a1e38244, test-shard scripts andci.yml); that commit touches none of the edited files or the gates above, and the branch is left on the dispatch base so the readings stay pinned to one tree.Not done here, on purpose
scripts/pm/os-verify-lock.sh(--depth/--json): the file surface of this card is.claude/skills/pm-dispatch/**; the counting rule is the documented one-liner above.references/dispatch-runbook.md(headroom 0; the rule and the counting form fit inSKILL.md)..claude/agents/os-dev.mduntouched — Dev contract: the verify-lock waiting discipline (acquire once, stay blocked, always name OS_VERIFY_LOCK_SLOT) — the #14944 ruling's Q3 A half #16262 remains open.skip-changeset).Open questions for the maintainer (not decided here)
priority:p0vs the depth hold. The ruling is silent. Written here as: p0 still exceedsbatchbut does not cross the depth hold — the hold protects gate measurement, and a p0 card gains nothing from a NOT MEASURED gate. Overrule by editing one clause in each of the two files.LOCK_DEPTH_HOLD = 2is named in prose. The skill's existing convention for numbers it reads (CONTRACT_REVIEW_TIER,GOVERNED_APPROVERS) is a single source inscripts/pm/dispatch-gates.mjs/ the queue guard. Moving it there is ascripts/pm/**edit — outside this card's declared surface — so it is left in prose; say the word and it becomes a one-line constant plus a pin.batchdefault.SKILL.md's argument table still lists thebatchdefault as3while the ruling calls the nominal cap 5 (2026-09-03). Not changed here (the ruling says the cap is unchanged, not that the default is); flagged for the seat.维护者速读(草稿)
--status),到达深度 ≥ 2 就等,不派;batch名义上限 5 不变;priority:p0仍可超batch,但不越过这个等待。规则同时写进 SKILL.md 与 core-rules.md。--report回贴 exit-99 率,卡片以那次读数关闭。Generated by Claude Code