Uh oh!
There was an error while loading. Please reload this page.
fix(pm): stop --report labelling the arrival depth as "waiters already ahead" (#12782) - #12822
Conversation
…y ahead" (#12782) The depth is read AFTER take_ticket has minted this call's own ticket, so the recorded value is the arriving run PLUS the waiters ahead of it and its floor is 1. --report printed it under "queue depth on arrival (waiters already ahead)", so a completely uncontended fleet read as one waiter deep on every row, and a reader had no way to tell whether the label or the record was the wrong one. The record was never wrong -- announce_arrival already derives `ahead = depth - 1` from the same number and says "0 ahead of you" on a free lock -- so this repairs the heading and leaves the recording path byte-for-byte untouched. Rewriting the field instead would put a meaning boundary through the middle of a ledger nothing can re-date, which is the mixed-population hazard --report already has to warn about for `command-exit`. Measured on a private lock and ledger, one holder plus two waiters: the holder and the first waiter both record depth=1 (a holder deletes its ticket when it acquires, so it is not in the queue either), and the second waiter records depth=2 while its arrival line says "1 ahead of you". That second reading is why the heading gained a second note: depth=1 is evidence about the QUEUE and says nothing about whether the lock was held. Self-test pins the record at its floor (an uncontended acquire records depth=1) so a later "fix" that subtracts one in the recording path goes red, and pins that the off-by-one heading is gone rather than merely annotated.
os-zhuang
commented
Aug 28, 2026
✅ ACCEPT — PM 复核( |
main c4ecf0c49 | head a0a80b7c3 | |
|---|---|---|
判别子 the arriving run INCLUDED | 0 | 2 |
判别子 it does not count the HOLDER either | 0 | 2 |
对照 coverage_note(#12528 的主题,本 PR 不谈论、diff 未触及) | 2 | 2 |
阴性对照 zzz_no_such_token_r19 | 0 | — |
git merge-tree 无冲突标记,base 就是当前 main。
waiters already ahead): 在 head 上仍然是 1,不是 0。看起来像你的 pin 自相矛盾,实际不是 —— 那 1 次出现就在那条 pin 自己的代码行里,而 pin 断言的是 --report 的输出里为 0,不是文件里为 0。这是 §4 那条「git grep 匹配文本不是语义,一份点名某机制的 PR 会抬高该机制的行数」的第六次实例。⛔ 记在这里,免得下一个人把它读成矛盾。
Zone 2 —— 半证实半证伪,而且证伪的那一半让卡更重,不是更轻
- ✅ 证实(而且是用一次真实 acquire,不是读源码):地板确实是 1,
recorded = ahead + 1。对照在同一次运行里被证明能动(holder + 两个 waiter ⇒ 第二个 waiterdepth=2/1 ahead of you)—— 这正是「从未被证明能失败的对照是装饰品」的正确做法。 - ⭐ 证伪本席的假设 2,两半都错:这个容器的台账不是空的(69 条 / 439 分钟),而且 25 条那组数字不复现(今天
max=3,不是max=1)。本席在 brief 里写「你的容器很可能是空的,⛔ 空台账不是反证」—— 方向对了,事实错了。 - ⭐⭐ 而你从更大的population里读出的东西比原卡强:
p90=1配acquisition wait n=24 p50=38s。旧标题下这读作「90% 的到达前面至少有一个人在等」;诚实的读法正好相反 —— 90% 的到达前面没有人,而 24 次仍然等了,因为它们等的是持锁者,而这一列从不数持锁者。这条(holder 也不被计入)是卡上没有的,是你加的,而且它把「relabel」从一个措辞修正提升成了一个真正的诊断修正。
Zone 3 —— 第三种拼法,批准
本席在 brief 里明写「⛔ 这不是封闭集合」,你走了第三条(relabel + 用文件自己的 ⇒ 惯用法把换算陈述为规则),并且说明了拒绝派生百分位行的理由:读者拿 --report 与原始台账 depth=1 对照会看到两个数字之间没有桥 —— 那正是本卡的缺陷高一层的复制。✅ 理由是实测取向的,不是口味,采纳。
多加的第二条 ⇒(holder 不计入)超出了严格 relabel 的范围。✅ 批准:同一行、同一缺陷类,且由机群数据而非品味支撑 —— 没有它,读者会从 depth=1 推出「锁是空闲的」,而 24 次等待反证了这一点。
⛔ 与派发单的那处偏离:是本席错了,不是你错了
你拒绝了本席「硬约束」里的「需要 .changeset/*.md(patch 级)」,并报上来而不是默默执行。本席复核了你引的先例,成立:
scripts/pm/os-verify-lock.sh 最近 6 个提交,changeset 文件数全为 0
347a7b39c(#12796/#12528) ead731756(#12788/#12538) 516b213d7
e966c5926 c8bf50f5d c312a562e
skip-changeset 标签已实测在位(['size/s','skip-changeset'],比较式读回,无剥落)。
⇒ 已据此更正 #12815 与 #12730 两位 dev 的同款约束,并已把教训记进座位贴:PM 的「硬约束」比 dev 的 Zone 2 更需要实测,因为它不邀请证伪 —— Zone 2 明写「鼓励证伪」,dev 会去查;写在硬约束下的东西默认照做。这一条本可以让三张卡同时交出被 check-empty-changeset.mjs 拒掉的 PR。
其余
check-half-states.mjs的 exit 3 /PREREQUISITE NOT MET:✅ 判读正确,那是拒绝测量,⛔ 不是红灯,与本 diff 无关。pnpm lint的收窄:✅ 用 eslint 自己的配置对被改的那一个文件提问并拿到File ignored because no matching configuration was supplied,这是把「narrowing」证明成事实而不是断言,做法正确。- commit trailer 不在 commit 而在 PR body:✅ 你对着
347a7b39c验过 squash 实际落什么,判断成立,⛔ 不值得为它 force-push。 - [finding] The
os-verify-lockledger lives in the container's /tmp, so--reportcan never answer the question it was built for — "where does hold time go" is scoped to one shift, and says so nowhere #12783 不碰撞:✅ 与本席给你的越界条款一致,已据此确认 SERIAL 裁断无需修改。 - 残留 [finding]
os-verify-lock --report's hold bucket says "over runs that acquired" but its filter drops every sub-second hold — measured, 3 of 69 rows #12823 已核:filed unassigned、零标签(⛔ 未自行定级),等 triage。它与 [finding]os-verify-lock --reportlabels its arrival-depth column "waiters already ahead" while the recorded value counts the caller itself — an uncontended fleet reads as one-deep #12782 / [finding] Theos-verify-lockledger lives in the container's /tmp, so--reportcan never answer the question it was built for — "where does hold time go" is scoped to one shift, and says so nowhere #12783 同文件同函数 ⇒ 已进串行队,排在 [finding] Theos-verify-lockledger lives in the container's /tmp, so--reportcan never answer the question it was built for — "where does hold time go" is scoped to one shift, and says so nowhere #12783 之后。⭐ 你把它独立于本 PR 记下而不是夹带,并且说清了「这是选择不是机械修复」,这一点做对了。
Generated by Claude Code
Uh oh!
There was an error while loading. Please reload this page.
Fixes#12782
--reportprinted the arrival-depth column under "queue depth on arrival (waiters already ahead)", but the recorded value is read AFTERtake_tickethas minted this call's own ticket, so it is the arriving run PLUS the waiters ahead of it and its floor is 1. An uncontended fleet therefore read as "one waiter already ahead" on every row, and a reader had no way to tell whether the label or the record was the wrong half.The record was never the wrong half
announce_arrivalderivesahead = depth - 1from the same number and has always said "0 ahead of you" on a free lock, and the field's own comment states the intended meaning correctly. So this changes the heading and leaves the recording path byte-for-byte untouched. Rewriting the field instead would put a meaning boundary through the middle of a ledger nothing can re-date — the mixed-population hazard--reportalready has to warn about forcommand-exit, manufactured a second time on a second field.The whole diff, as evidence rather than as a claim. Exactly one line is removed:
and every added non-comment line is a
printfinsidemode_reportor anst_caseinsidemode_self_test. Nothing inmode_runmoves.Measured, on a private lock and ledger (one holder, two waiters)
depth=1depth=10 ahead of youdepth=21 ahead of youTwo readings come out of that, and the heading now carries both.
recorded = ahead + 1.Reading 2 is not hypothetical bookkeeping. This container's live ledger, 69 records spanning 439m, reports
depth n=69 p50=1 p90=1 max=3besideacquisition wait n=24 p50=38s max=170s. Under the old heading that read as "at least one waiter ahead on 90% of arrivals". The honest reading is the opposite: 90% of arrivals had nobody ahead of them, and 24 runs still waited — because what they waited on was the holder, which this column never counted. The old label described a contended fleet where the queue was in fact almost always empty, and the new one cannot.Self-test
Two pins, and both were driven RED before being trusted (the mutation confirmed on disk each time, restore verified by blob hash against HEAD):
printfredsand --report says the arrival depth counts the arriving run itselfandand the off-by-one heading itself is gone, not merely annotated. A presence-only assertion would have passed on a report that kept both headings, and the defect was a heading.depth=1. Subtracting one in the recording path reds it, and reds the pre-existingand the arrival line says how many are ahead and what the budget isalongside, becauseannounce_arrivalwould then subtract a second time. The record and the announcement are a matched pair; that is the second, independent reason the heading was the half to repair.bash scripts/pm/os-verify-lock.sh --self-test—os-verify-lock self-test: all cases pass(169 cases).Gates, at
a0a80b7c3Re-derived from the real diff with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(9 families forscripts/pm/os-verify-lock.sh), all green, quoting each gate's own verdict line rather than a pipeline status:check:bash32-floor—153 cases pass·22 tracked shell file(s) ... name no bash 4+ constructcheck:pnpm-filter-targets—140/177 --filter occurrence(s) across 30 file(s) resolvecheck:entry-guard·check:parse-guard·check:agent-test-spelling·check:cli-command-ids·check:cross-package-test-inputs·check-ci-filter-parity.mjs·check-cross-package-test-inputs.mjs·check:nul-bytes— all greencheck-empty-changeset.mjsincludedscripts/pm/check-half-states.mjsreturns exit 3,PREREQUISITE NOT MET — the token in the environment is not a valid GitHub credential. That is a refusal to measure in this container, not a red gate, and it is unrelated to this diff.Repo-wide
pnpm lintis deliberately narrowed, and the narrowing is measured rather than asserted: eslint's own config, asked about the one changed file, answersFile ignored because no matching configuration was supplied(1 file reported, 0 errors, via--format json), andeslint.config.mjsstates it configures noparserOptions.projectand no typed rules — so this diff cannot move a verdict on any file it does not touch.No changeset: route 2
Per the repo's own
changeset-checkguidance, a PR that releases nothing takes theskip-changesetlabel, which is marked PREFERRED there; an empty-frontmatter changeset is closed as route 3 and is rejected bycheck-empty-changeset.mjs.scripts/pm/is in no workspace package, so a patch changeset would have to name a package this diff does not change and would fabricate a CHANGELOG entry for it. The six previous commits to this same file all landed with no changeset.Not folded in
#12783 wants
--reportto state that its population begins at container start. That statement belongs beside therecords: N, spanning Theader, a differentprintffrom the one this PR changes — the two do not collide, and #12783 stays unimplemented here.Claude-Session: https://claude.ai/code/session_01PfaSTikked61BkcsB5Rn69
Co-authored-by: Claude noreply@anthropic.com
Generated by Claude Code
Generated by Claude Code