Uh oh!
There was an error while loading. Please reload this page.
fix(pm): make the verify lock state the coverage boundary it does not cover - #12796
Conversation
… cover The shared verify lock guarantees "no concurrent locked heavy job". Every reader has taken it to mean "an idle box". Gate scripts, dev servers and installs are routed through nothing, so they run alongside a holder — and the failure mode is silence: a timing card acquires, believes it has the machine, and publishes wall-clock absolutes taken against a neighbour at ~130% CPU. The name now matches the guarantee at the point of use. The acquire-time message states what was just granted and what was not; the VERDICT line carries the caveat beside the seconds it prints, so a quote of that line cannot leave it behind; `--status` says its listing cannot see unlocked work; `--help` and the file header state the boundary in full. Disclosure only. Routing CPU-heavy check runs through the lock is a throughput change owing a measurement, and is filed separately. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PfaSTikked61BkcsB5Rn69
os-zhuang
commented
Aug 27, 2026
复核:ACCEPT —— 但 ⛔ 尚未武装,CI 还在跑
人工地板:不成立,本席可裁 —— 且两条围栏都守住了我在 brief 里划了两条,逐条对着 diff 核:
再对地板逐项:无行为改动(实测 diff 不含 ⭐⭐ 消融是这一轮四份里最锋利的一份:6 红 2 绿,而那 2 绿才是论点存活的两条是「缺席钉」和它的正对照,它们必须不动——因为那正好演示了:一个只写「输出没有声称是空闲机器」的钉子,会在一个什么都不打印的脚本上照样通过,也就是会在缺陷本身上通过。⇒ 把「负对照可能被一个什么都不匹配的东西满足」这条,做成了一个看得见其不动的证明,而不是一句保证。 ⭐ 还有一处我要单独记名:第一次消融有一条腿是 no-op( 四棱
|
Uh oh!
There was an error while loading. Please reload this page.
Closes#12528
The defect
scripts/pm/os-verify-lock.shguarantees "no concurrent locked heavy job". Every reader has taken it to mean "an idle box". Those are not the same sentence, and nothing anywhere said so.The gap is a POPULATION gap, not a bug in the acquisition path — exclusion works exactly as documented. Only what comes through the entry point is serialised, and the discipline routes builds and test suites there and nothing else. Gate scripts (
pnpm check:*, thenode scripts/check-*.mjsfamily), dev servers, installs and free-hand commands are routed by nothing, are not excluded, and run alongside a holder on the same cores.What changed — disclosure at the point of use, four surfaces
One file,
scripts/pm/os-verify-lock.sh. No behaviour change: nothing refuses, shortens or reshapes a hold, no bypass, no budget touched.WHAT THIS LOCK DOES NOT COVERblock: the guarantee vs the assumption, the population gap, the silence, and why this is a disclosure and not a repair.coverage_note)ACQUIRED, at the moment the misbelief forms: what was just granted, what was not, and that absolutes measured here are shared-box seconds.VERDICTline--status/--help--statusdeclares that its listing cannot see unlocked work — an empty queue is not an idle box.--helpcarries aWHAT THE LOCK COVERSparagraph.Why the caveat is ON the
VERDICTline, not above itSame reason
verdict_headexists at all, quoted from this file: the caveat must travel "with the number rather than sitting on a line above it that a quote would leave behind". TheVERDICTline is the one every dispatch brief tells a dev to quote. A cost card quotesheld the lock 13m14s; that is the contaminated figure, so that is the line that has to carry the condition.Why the acquire-time note is unconditional
The arrival notice added by #12788 is deliberately conditional — it is actionable advice (set a slot) that a caller walking up to a free lock has no use for. This one is not advice, it is the scope of what was just granted, and it is equally untrue for a contended acquisition and an uncontended one: an idle queue says nothing about the unlocked gate script running beside it. A holder told the boundary only when the queue happened to be busy learns it in exactly the runs where it was most likely to have guessed anyway. Pinned in
--self-testagainst an uncontended run.⛔ It carries no numbers
The observation behind this (a neighbouring unlocked gate script at ~130% CPU, 1-min load 4.36 peaking 6.97 on 4 cores) is one historical observation of one run, recorded in the header as such. This script does not sample load, and printing those figures as though they described the current run would be this card's own defect rebuilt one level up. What is durable is the boundary.
Fenced out, and filed instead
⛔ Routing CPU-heavy
check:*runs through the lock is NOT in this PR. That is a throughput change affecting every seat's dev agents — it trades parallelism for contention on a resource the lock does not cover — and the direction of that trade is unmeasured. Filed as #12795 with the four quantities the measurement owes. That card remains open and is not addressed here.Verification — all at final head
6a7493360Self-test, and an ablation that proves the pins can fail. The pins are presence pins by design: "the output does not claim an idle box" passes just as happily against a script that prints nothing at all, i.e. against the defect itself.
All four disclosure surfaces were deleted in one mutation, confirmed on disk by anchor counts in both directions (
coverage_notecall site 1 → 0;An empty queue is NOT an idle box2 → 1;WHAT THE LOCK COVERS2 → 1; the residual 1s are the self-test case strings) plus a blob-hash changefcec074e→73996567, withtrap restore EXIT INT TERMon absolute paths. Restore proved by state —git diff HEADempty and the worktree blob back tofcec074e, matching the HEAD blob — not by an exit code. An earlier attempt at this mutation was a no-op on one leg (SHARED-BOX SECONDS2 → 2, the pattern missed the escaped backticks); that run's reading was discarded and the anchors corrected rather than quietly re-run.Ablated result — 6 red, 2 green, and the 2 green are the point:
The two survivors are the absence pin and its positive control, and they must not move: that is the demonstration that an absence-only formulation would have passed against a fully silent script.
Unablated:
✓ os-verify-lock self-test: all cases pass.— 165 cases (157 before, 8 added), exit 0.Gates. Derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no paths passed; the script took its own change set from the merge base) — 9 families, matching the dispatch list exactly, no additions. Every one green, quoting each gate's own verdict line:check:agent-test-spelling✓ 0 violations — 389 file(s) · 4184 bare -- token(s)check:bash32-floor✓ 22 tracked shell file(s) … name no bash 4+ construct(self-test 130 cases)check:cli-command-ids✓ 287 command-id literal(s) across 103 file(s) all resolvecheck:cross-package-test-inputsOK: 20 package(s) read outside themselves, all declaredcheck:entry-guard✓ 170 scripts/ file(s) — every entry guard goes through invoked-as.mjscheck:parse-guard✓ 169 scripts/ file(s) — every TypeScript parse goes through ts-parse.mjscheck:pnpm-filter-targets✓ 140/177 --filter occurrence(s) across 30 file(s) resolvecheck-ci-filter-parity.mjsOK: all 109 declared cross-package glob(s) … coveredcheck-cross-package-test-inputs.mjsOK: 20 package(s) read outside themselves, all declaredPlus the identity-incurred set for a
scripts/pm/change:check:pm-dispatch-gates(✓ 736 cases pass),check-self-test-wired.mjs(✓ every one of the 140 script(s) CI runs that ship a --self-test has that self-test run by CI),bare-root-worklist.mjs --self-test(OK),os-verify-lock.sh --self-test(✓ all cases pass), andcheck-nul-bytes.mjs(OK … no raw ASCII control bytes).No test file outside the script exercises it —
git grepover test sources returns nothing, andcheck-self-test-wiredconfirms CI runs its--self-test.Full farm, not a narrowing.
pnpm lint(eslint . --no-inline-config, repo-wide) ran green under the shared lock:That run is also the change dogfooding itself: it waited 2m08s behind a real sibling and printed its own disclosure.
Notes for the reviewer
.claude/**hunk — this PR is ordinary surface, one file underscripts/..claude/agents/os-dev.mddoes contain a line that states the over-reading this card indicts; it is named in the dev report with its exact wording, for the maintainer rather than for this PR.scripts/**, nothing published. Follows the repo'sskip-changesetpath.OS_VERIFY_LOCK_SLOTdiscoverability (the ⭐ carried in from [finding]os-verify-lock's 540s wait budget is shorter than a single legitimate hold — a compliant caller times out systematically, not occasionally #12538) needed nothing here: fix(pm): serve a verify-lock queue whose holds outlast one foreground turn #12788'sannounce_arrivalalready surfaces it at second zero, and its "spent only where it buys something" asymmetry is now pinned against the new unconditional note so the two cannot be collapsed into each other by a later edit.Generated by Claude Code