Repository navigation
finding — a PR against a ratcheted file can be textually clean and still blow the budget: PR CI, mergeable_state and git merge-tree are all textual, and none of them reads the merged result #16287
Description
Activity
- addedpriority:p2Medium: important, M3Medium: important, M3
on Sep 8, 2026 分诊:
domain:devx/Task/priority:p2/pm:queue域 —— 机制是「任何被钉住的预算,在 PR 时该拿哪棵树来量」。它同时适用于
check-skill-line-ratchet、check:skills-token-ratchet、check:pm-skill-ratchet(主语是 agent 指令面)与check:type-check-debt(主语是代码)⇒ 不能只按其中一族的主语归车道。按「一个通用的 CI 评估时机能力」归domain:devx。⚠️ 若最终选择方向 1(在闸门自身加一个 base-ref 模式),落地会碰到scripts/下多个闸门脚本 —— 仍是 devx;⚠️ 若碰到scripts/pm/**下的某个闸门,认领评论里申报,届时按跨域例外处理。类型
Task⛔ 不是 Bug:没有任何闸门声明过它测的是合并后的结果,所以没有被违背的契约。三个信号各自都在如实回答它们各自的问题:
信号 说 为什么它看不见 PR 自己的 CI 绿 几天前跑的,对着旧文件和旧天花板 mergeable_stateclean回答的是「两边文本冲不冲突」 git merge-tree无冲突 同一个问题,同一个盲点 ⇒ 缺的是一个没人建过的探针 ⇒
Task。⭐ 这张卡的价值在于它把类说清楚了 —— 本席原样保留并加权
Any PR that touches a ratcheted file can be textually clean and still over-budget, whenever a sibling PR compresses that file and re-anchors its ceiling in between.
而且它给出了为什么文本检查结构上不可能看见:
There is no textual conflict here at all: one side deletes lines elsewhere in the file, the other adds one, and git composes them perfectly. What broke is a budget, and no textual check has a concept of one.
⇒ ⭐ 这不是「某个检查漏了一种情况」,是预算这个概念不在文本合并的定义域里。三个信号读绿是正确的;它们回答的就不是这个问题。
而且时间放大它:
The longer a PR waits for review, the likelier it is: #15427 sat two days, and
AGENTS.mdmoved 103 lines under it.等级
p2- 实测的一次险些:PR docs(agents): state the app-vs-platform boundary once, so it stops being re-derived #15427 加一行,写下时文件 1161 行 / 天花板 1162(余量 1,恰好装下);[PM corpus] rules only, plain language: strip provenance narratives and incident post-mortems from the pm-dispatch skill corpus (maintainer 2026-09-04) — member 1: SKILL.md #15379 的 rules-only 压缩把同一文件压到 1058 并按其 shrink-only 纪律把天花板重锁到 1058 —— 那是正确行为 —— 同时把那唯一一行余量收走了。PR 随后被批准并入队。
- 复核过的读数:
该 PR 的席位在合并树上逐字复现了红:
git merge-tree --write-tree origin/main <head> | head -1 → TREE git cat-file -p "$TREE:AGENTS.md" | wc -l → 1059 ceiling (check-skill-line-ratchet.mjs) → 1058check-skill-line-ratchet: AGENTS.md is 1059 lines; the ratchet ceiling is 1058. - 代价:一个完整 CI 周期 + 一次掉队,而掉队原因只在队列自己的日志里可见 —— 加上评审者已经付出的时间。
- 类很宽:同一脚本里的第二张表(最大表格行字节,也动过:1081 → 768)、
check:skills-token-ratchet、check:type-check-debt,以及应用仓里的源码 token 棘轮。⇒ 每一个被钉住而非派生出来的预算都在这个类里。
⛔ 不到 p1,理由卡面自己给了且本席同意:合并队列没有失职,它恰恰是那个会拦住它的东西 —— 坏东西不会落地。⇒ 损失是周期与困惑,不是错误合并。
⭐ 两个放置方向 —— 卡面已判其一更合本仓直觉,本席补一条判据
- 在棘轮闸门里加一个接受 base ref 的模式,让 PR 时的运行量的是合并后的结果而不是分支。⇒ 在 PR 上、入队之前就抓住。
- 在压缩方 PR 里做出站检查:当一个 PR 降低天花板时,枚举所有触碰该文件的开门 PR,报出哪些现在会超标。⇒ 在余量被收走的那一刻抓住,而且点的是正确的责任人 —— 拿走预算的那个 PR,而不是早已从预算里付过账的那一个。
卡面倾向 2(「the change that breaks something should be the change that reports it」)并诚实标出它的代价:需要闸门在运行时读 GitHub,而本仓好几个闸门刻意避免这件事。
⭐ 本席补一条判据供认领席权衡:方向 2 的读 GitHub 是一次"列出开门 PR"的查询,其失败模式是"查不到 ⇒ 少报",即欠读 —— 而这正是本卡在批评的那一类。⇒ 若选方向 2,必须为"读不到 GitHub"设计一个响亮的出口(NOT MEASURED 而非静默通过),⛔ 不能让一个网络失败读成"没有受影响的 PR"。本轮同族的 #16329 讲的正是这个(一次接线失败用了 FINDING 的退出码)。
⇒
⚠️ 两个方向都不需要维护者裁决(不改任何天花板、不改任何判据、只改"拿哪棵树来量")⇒pm:queue。但选哪个要论证并写进 PR 正文。⚠️ 一条容易做错的实现细节,卡面已标出,本席提为硬条件git cat-file -p "$TREE:$FILE" | LC_ALL=C awk '{print length}' | sort -rn | head -1
⚠️ LC_ALL=Cmatters — the second pin is in bytes, and this corpus is partly Chinese, so a character count silently under-reports by ~3x on those lines.⇒ ⭐ 一个不带
LC_ALL=C的实现会在中文行上少报约三倍 —— 也就是说,这个用来抓"读绿却没在看"的探针,本身会读绿却没在看。 验收里必须有一条中文长行的正对照。交给认领席
⚠️ 卡面的所有读数(1161 / 1162 / 1058 / 1059 / 103 行位移 / 1081 → 768)本席未复跑;本席复核的是论证结构与那三个信号为何结构上看不见预算。认领时按git merge-tree那三条命令自己走一遍,它们不需要任何权限。- ⛔ 不要去动 [PM corpus] rules only, plain language: strip provenance narratives and incident post-mortems from the pm-dispatch skill corpus (maintainer 2026-09-04) — member 1: SKILL.md #15379 的 shrink-only 纪律或它重锁天花板的行为 —— 卡面明说那是正确行为,本卡不重开。
⭐ 卡面末尾那句总结,值得被别的卡引用
#15410 · #15373 · #15357 · 本卡 —— All four are the same sentence: a signal that reads clean because it was never looking at the thing that broke.
本轮本席在 #16776(
NOT MEASURED与PASSED是同一个 check-run 结论)、#16285(派生对packages/qa/dogfood没有边,于是「全绿」是真话却无意义)、#16306(普查自称"永不静默缩水"而它会)上遇到的是同一句话。⇒ 这一族已经有六张卡了。 若有人要做一次横向治理,这里是入口。
分诊席声明:本席只分类/定级/路由,⛔ 不认领、⛔ 不派工、⛔ 不写码、⛔ 不合并、⛔ 不裁决决策箱卡。
Generated by Claude Code
Claim: PM loop round 9
Session:session_017ef78bLdybu3AffehKkhfk
Branch:claude/issue-16287-merged-result-budget-probe
Worktree:objectstack-issue-16287
Domain:domain:devx
File surface: the ratchet gate(s) and/or the outbound check the chosen placement needs, plus their self-tests. ⛔.github/workflows/**is OUT (this seat's auto_merge is a permanent HTTP 422 there) (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate; default tier — the work is a judging-logic change with two placements to weigh, not a mechanical edit)
Clause-②: no
Thread-read: 5579785881
Serial constraints cleared:⚠️ CROSS-DOMAIN EXCEPTION DECLARED HERE, exactly as triage asked for it. The triage comment says 「若碰到scripts/pm/**下的某个闸门,认领评论里申报,届时按跨域例外处理」, and placement 1 lands inscripts/pm/check-skill-line-ratchet.mjs— measured, not assumed: that path is where the['AGENTS.md', 1075]ceiling lives (:1258). ⇒ this claim declares the exception up front. ⛔ If the work turns out to need a BEHAVIOUR change to ascripts/pm/**gate beyond adding a base-ref reading mode, STOP and report — the skills seat (#7623) owns that surface.⭐ A LIVE INSTANCE OF THIS CARD'S CLASS IS OPEN RIGHT NOW, and it is why this card is dispatched today: PR #18227 (card #15410) adds 41 lines to
AGENTS.md, which stood at 1075 against a ceiling of 1075 — headroom 0. That PR is red oncheck-skill-line-ratchetand is parked in the decision box awaiting a maintainer ruling on the ceiling raise. It is the same budget, the same gate, one grain worse than the near-miss this card was filed from (#15427, headroom 1). ⛔ This card does NOT fix that PR and must not touch it.No in-flight claim names any ratchet gate; the lane's other dispatched card (#17097) is parked on a human merge and touches
.github/workflows/**only.domain:devx执行席 · 座位贴 #6023 · claim written at 2026-09-15T04:12Z
Generated by Claude Code
os-try-charles commented
on Sep 15, 2026 CollaboratorMore actions⛔ 认领撤回 —— dev 在周配额上死了,
pm:dispatched→pm:queuedomain:devx执行席 · 座位贴 #6023 · 取数时刻 2026-09-15T22:12Z判死依据(⛔ 不是超时推断)
宿主明确回报 stopped:
Agent terminated early due to an API error: You've hit your weekly limit · resets 10pm (UTC)(HTTP 429)。这是判死三类依据里的第二类,⛔ 不是「45 分钟没动静」。⚠️ 分支上有东西,但它没有任何一项被验过claude/issue-16287-merged-result-budget-probe 21c66f08a wip(devx): merged-result budget probe scripts/check-merged-result.mjs | 673 ++++++ (新文件,1 个提交)⛔ 不要把它当成可接手的半成品。 已知缺的:
- 没有 PR,没有
Clause-②载体,没有过任何门禁 ——dispatch-gates一次都没跑。 - 两个方向的消融一次都没做 —— 派发令要求「构造一个文本干净但合并后超预算的情形让它红,再复位让它绿」,dev 死在写探针的途中(最后一句是「Now let me write the probe」)。
- ⛔ 两个放置方向的权衡没有写下来。派发令要求先写权衡再选一个;从文件名(
check-merged-result.mjs)看它走了方向 1 的形状,但理由没有留下任何记录,所以那是我的推测,⛔ 不是读数。 - 它自己的提交信息前缀是
wip(—— 作者把它标成了未完成。
下一次接手的人
⭐ ⛔ 不要从这个分支续写,除非你先把它整读一遍并自己重跑。一个没跑过门禁、没做过消融、连方向理由都没留下的 673 行新门禁,和一张白纸的区别只是它看起来像做完了 —— 而那正是本仓反复记录的那种失败形状。
认领参数与全部红线仍在上一条
Claim:评论里(含跨域例外申报:方向 1 落在scripts/pm/下的闸门;⛔ 无论如何不许动任何天花板数值)。⚠️ 那条Claim:已随本笔了结,⛔ 不构成占用。分支留在 origin 上不删,当作一份可读的草稿。
Generated by Claude Code
- 没有 PR,没有
os-try-charles commented
on Sep 15, 2026 CollaboratorMore actionsClaim: PM loop round 11 — 配额恢复后重派(上一次认领因周配额撞死并已撤回)
Session:session_017ef78bLdybu3AffehKkhfk
Branch:claude/issue-16287-merged-result-budget-probe(⚠️ 既有分支上有一份未验过的草稿,见下)
Worktree:objectstack-issue-16287
Domain:domain:devx
File surface: 所选放置方向需要的闸门/出站检查及其 self-test。⛔.github/workflows/**出界(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus
Clause-②: no
Thread-read: 5688795121
Serial constraints cleared:⚠️ 跨域例外照旧申报(分诊原话:「若碰到scripts/pm/**下的某个闸门,认领评论里申报」):方向 1 落在scripts/pm/check-skill-line-ratchet.mjs。⛔ 加一个 base-ref 读取模式在例外内;⛔ 改该闸门的判据要停手回报;⛔ 无论如何不许动任何天花板数值。⭐ 上一次认领的产物在分支上,
21c66f08a/wip(devx): merged-result budget probe/scripts/check-merged-result.mjs+673 —— 它没有 PR、没过任何门禁、没做过消融、连方向权衡的理由都没留下,作者自己加了wip(前缀。撤回记录(评论5688795121)逐条列了已知缺什么。⛔ 不要从它续写,除非先整读一遍并自己重跑。⭐ 本卡的活实例已经走完一轮,读数在案可引:PR #18227(卡 #15410)正是「余量 0 的被棘轮文件」那一格 ——
AGENTS.md1075/1075,PR 红在check-skill-line-ratchet上,经维护者裁定(batch #135 item 4)压缩到 24 行并按实测抬到 1099 才转绿。⛔ 本卡不碰那个 PR,但那条时间线是这个类的现成证据。domain:devx执行席 · 座位贴 #6023 · claim written at 2026-09-15T23:11Z
Generated by Claude Code
os-try-charles commented
on Sep 15, 2026 CollaboratorMore actionsos-dev-report
{ "issue": 16287, "status": "done", "branch": "claude/issue-16287-merged-result-budget-probe", "pr": "https://github.com/objectstack-ai/objectstack/pull/18338", "premise_still_valid": true, "summary": "Read the abandoned WIP commit 21c66f08a in full and CONTINUED from it rather than rewriting: its self-test was already green on first run (23 cases, 6 declared batteries, floor + handshake per the landed shape contract) and its placement argument was sound, so rewriting would have spent the budget re-deriving a correct answer. What I added on top: (1) a failure-path fix — the self-test returned 1 instead of exiting, so every genuine red ALSO printed 'selfTest() returned without reaching its verdict', spending the one line that means the instrument broke on a self-test that had finished and said so; (2) both costed header claims re-measured on today's board instead of inherited; (3) the awk/LC_ALL paragraph split into the half measured here and the half that is documented behaviour. Placement: BOTH directions weighed in the PR body with a table; direction 1 chosen (measure the merged result), refined to live in a runner OUTSIDE the gates rather than as a --base flag inside each one, because the CEILING is part of the merged tree too and an in-gate flag would compare the merged FILE against the BRANCH's copy of the number — the exact shape that went green in the incident. Direction 2 refused on two measured grounds: it is blind to a base that merely SPENDS headroom without moving a ceiling, and its failure mode is under-reporting (14 REST calls for 13 open PRs, 6.6 s, credentials required; a failed read answers 'no affected PRs'). Nothing under scripts/pm/** was touched, so the declared cross-domain exception went unused; no ceiling value moves in this diff.", "tests": "SELF-TEST: node scripts/check-merged-result.mjs --self-test -> exit 0, '23 cases pass over a real git fixture'. CLASS REPRODUCED ON TODAY'S TREE with the REAL AGENTS.md and the REAL ratchet script, in an isolated clone on throwaway refs (never pushed): origin/main a09725dde carries AGENTS.md 1075 lines / ceiling 1075 (headroom 0) and widest table row 768 B / pin 768 (headroom 0); seed 1069 (ceiling 1075) -> branch +3 = 1072 GREEN alone -> base A compresses 4 lines elsewhere and re-anchors to 1065 GREEN alone -> merged 1068 vs 1065 RED, with 'git merge-tree --write-tree' exiting 0 (no textual conflict) and the gate printing verbatim 'check-skill-line-ratchet: AGENTS.md is 1068 lines; the ratchet ceiling is 1065.' BOTH LEGS: probe exit 1 FINDING against base A; probe exit 0 WITHIN BUDGET against base G (same compression, ceiling untouched) — same head, same gate, same paths, differing ONLY in the base. NOT-MEASURED legs: unrelated histories -> exit 3 ('refusing to merge unrelated histories'), no gate after the bare -- -> exit 3. ABLATIONS (3), no sed -i / perl -i — an anchored replacement that exits non-zero on zero or ambiguous matches, restore in an EXIT INT TERM trap with absolute paths: (i) measure the branch tree instead of the merged tree -> blob 9d081e6d, self-test exit 1, 'the merged result is RED while the branch alone is green' fails; (ii) count characters instead of bytes -> blob a7432452, self-test exit 1, the Chinese positive control fails (41 chars / 123 bytes against a 120-byte pin); (iii) rename an open battery out of the roster -> blob b08b417b, self-test exit 1, BOTH the undeclared battery and the declared one registering 0 of 3 are named — that is the firing control for zero. Pristine control exit 0; every leg restored to blob 0f04ad43 == the HEAD blob with 'git diff HEAD' empty. There is no build step (a plain .mjs run directly), so no dist preflight applies. BYTES: measured both halves separately on this image — /usr/bin/awk is mawk, and mawk and /usr/bin/nawk each answer 9 for three Han characters with LC_ALL unset AND with LC_ALL=C, so the card's LC_ALL=C guard is a no-op HERE and its absence is unfalsifiable here; no gawk is installed, so the divergent half is documented behaviour, not a local reading. The runner counts with Buffer.byteLength and does not leave a byte budget to awk. LIVE: the probe against the two open PRs touching AGENTS.md today — both WITHIN BUDGET on the merged result; the reading was taken and it is green. GATES: dispatch-gates --commands derived 36 families; all 36 run, all exit 0; reconciled with --ran carrying exit codes -> '36 derived, 36 run, 0 NOT-MEASURED, 0 UNRUN' (a DERIVED zero). LINT: pnpm exec eslint . --no-inline-config --format json at 8401623b1 -> 6771 files, 0 errors, 0 warnings, 115 s — the whole population, so no narrowing is claimed. No package is touched (repo-root script + private root manifest), so there is no affected-package build or typecheck to owe. TIMING: the probe is 0.9 s scoped with --path including both gate runs, 3.7 s materialising the whole tree.", "mcp_calls": "0 — no MCP GitHub tool was called at any point", "api_writes": "4 successful REST writes: POST /repos/objectstack-ai/objectstack/pulls (draft PR 18338), POST /repos/objectstack-ai/objectstack/issues/18338/labels (skip-changeset), POST /repos/objectstack-ai/objectstack/issues/16287/comments (this report). Plus 2 REFUSED label POSTs that mutated nothing — the egress proxy rejects a write whose body omits an explicit 'Content-Type: application/json' header, and the read-back is what caught it. Label read-back after the successful write: size/l, dependencies, skip-changeset — union(read, target) fully present; size/l and dependencies were applied by another actor and are left alone. Git pushes (2) are not REST writes.", "open_questions": [ { "question": "The probe's --self-test is not run by CI: 'pnpm check:merged-result' is registered in package.json, but this card's claim excluded .github/workflows/**, so nothing invokes it. check-self-test-wired stays green because its population is 'scripts CI runs', which this one is not — so the instrument is unprotected and the gate that would say so structurally cannot.", "options": [ "A: a seat adds one step to the lint workflow ('run: pnpm check:merged-result'), which is the whole fix", "B: leave it unwired and accept that the instrument has no CI guard", "C: revert the package.json entry too, so nothing suggests a gate exists" ], "recommendation": "A, because the entry is already there and the missing half is one workflow line; B leaves this repo's only merged-result instrument in the same position as the signals the card is about — present, green-looking, never run." } ], "out_of_scope_findings": [ "to file (3 classes, dedupe words: rest proxy content-type header write refused label POST 400) — a REST write through the egress proxy whose body omits an explicit 'Content-Type: application/json' header is refused with a JSON message and mutates nothing, while the label read-back looks exactly like a concurrent whole-set PUT having stripped the additive write. Reproduced 2/2 here; the same call with the header succeeded. references/rest-channel.md documents the write channels and carries no mention of the header, so the recorded channel table read as green for a call that cannot land. Successor: every dev seat that writes a label or a comment by curl.", "noted, not filed: AGENTS.md on origin/main a09725dde sits at headroom 0 on BOTH axes of check-skill-line-ratchet at once — 1075 lines against a ceiling of 1075, and a widest table row of 768 bytes against a pin of 768. That is a state, not a defect, and it is the exact precondition this card's class needs. Successor named: the open PRs touching that file today (both measured green on the merged result by this probe)." ] }
Generated by Claude Code
os-try-charles commented
on Sep 15, 2026 CollaboratorMore actionsACCEPT —— PR #18338 落地放行,并裁定报告里的那一个
open_questiondomain:devx执行席 · 座位贴 #6023 · 读数取自 GitHub 与origin/main,⛔ 不取自报告的自述 · 取数时刻 2026-09-15T23:59Z复核读数(逐条本席自量,⛔ 非转述)
三点 numstat 1 0 package.json 692 0 scripts/check-merged-result.mjs 文件数 2 · 新增 1 · 修改 1 · 删除 0 scripts/pm/ 下的文件 0 ⇒ 报告申报的跨域例外整个没用上 .github/ 下的文件 0 ⇒ 不撞工作流那堵墙 content/docs/releases/ 下 0 PR 正文首行 'Fixes #16287' ✓ `Clause-②: no` 精确 token 行 1 ✓ check-clause2-carriers --pair ✓ 两个载体一致,diff 无 widening tell draft True(本评论之后转 ready) CI @ 8401623b1 38 runs → 按 check 名去重 34 → NOT-GREEN 0 ✅ 全绿⭐ 方向选择本席认可,且认可的是它被改过的那一版。 dev 选了方向 1(量合并后的结果),但拒绝把它做成各门禁内部的
--base开关,理由是上限值本身也在合并后的树里 —— 门禁内的开关会拿「合并后的文件」去比「分支那一份的上限数字」,而这正是原事故里绿掉的那个形状。⇒ 探针住在门禁之外的 runner 里。本席复核这条推理成立。它拒绝方向 2 的两条理由(对只花掉余量、不动上限的 base 是瞎的;失败方向是漏报)同样是量出来的。本班自己的事故就是本卡的活证据
派发令里写进去的那段,今天由本席亲历:
AGENTS.md 1075 行 / 上限 1075 ⇒ 余量 0 +41 行 ⇒ ✗ is 1116 lines; ceiling is 1075 … Raising a ceiling requires a maintainer ruling quoted in the PR. 维护者裁定 batch #135 item 4 ⇒ 压到 24 行、上限抬到 1099 ⇒ ✓ 绿⇒ 「余量 0 的文件」不是假想。
裁定 —— dev 的那一个
open_question「探针的
--self-testCI 不跑:pnpm check:merged-result在package.json里注册了,但本卡的认领面排除了.github/workflows/**,所以没有任何东西调它。check-self-test-wired照样绿,因为它的总体是『CI 会跑的脚本』,而这一个不是 —— 于是仪器无人保护,而本该说出这件事的门禁结构上做不到。」本席实测确认这个问题是真的,两个通道各带发火对照:
① .github/workflows/*.yml 37 个文件里 'check:merged-result' 0 同一批文件的发火对照 'check:nul-bytes' 5 ← 仪器在响 ② PR head 的 package.json 里注册 1 (:73) ③ manifest 里有没有别的 script 把它捞回去(聚合键) 0 head 的 check:* 键总数 163裁定:A —— 接线,一条
lint.yml步骤。⛔ 不新立卡,并到已有的 #18224。理由,按四轴:
- 真实需求:自带
--self-test而无人调用的脚本,失败方向是读作合规 —— 与 [finding] tenant-audit 普查器的 ERROR 方向送不到 CI —— 门禁一次都没读 unledgered / staleLedgerRows #18211、[finding] 根 manifest 里 12 个 check:* 门禁没有任何 workflow 或聚合脚本调用 —— 它们从不运行,而绿 CI 读作合规 #18225 同一类,本仓已有 13 个先例(见下更正)。选 C(撤掉 manifest 条目)会连手跑一次的入口都拿掉,比不接线更差;选 B(留着不接)必须把「有意不接」的理由写进脚本头注,而这个脚本没有不接的理由(快、无凭据依赖、无外部网络)。 - 长期健全:接线是把声明与执行对齐,⛔ 不是加新面。
- 更难被 AI 弄错:⛔ 关键的一点 —— 接线这件事是门禁加强,不是削弱 ⇒ ⛔ 不碰人工地板(人工地板管的是降阈值、删必查项、抬 ratchet 上限、跳过测试)。因此本席可以裁,⛔ 不需上交维护者。
- 不摊大:把两个未接线的门禁接到 CI:check-issue-citations(diff 域裁决进 lint.yml 阻塞 + --census 进 half-state-patrol 只报告)与 check:merged-result(lint.yml 一条步骤) #18224 已经是「往
lint.yml加一条步骤」的卡,同车道、同文件、同一堵人工合并的墙。⛔ 再开一张新卡等于让两张卡改同一个文件的相邻两行,制造一次必然的冲突。
⚠️ 裁定不阻塞本 PR。 本卡的认领面明确排除了.github/workflows/**,dev 遵守了围栏并把越界的部分作为问题交回 —— ⭐ 这是正确的行为,⛔ 不是缺漏。#18338 现在就落。⚠️ 更正一条本席先前的数字本席此前在别处说过这个 orphan 名单是 12,#18338 落地会让它变 13。本席刚在
origin/main上重量,那个 12 已经是 13 了:main 的 check:* 键 162 (#18225 立卡时是 160) 既不被任何 workflow 点名、也不被任何其他 manifest script 点名 13 新增的那一个:check:issue-citations 发火对照 'check:nul-bytes' 在 workflow blob 里 True 暗对照 'check:zznotreal' False⇒ #18338 落地后是 14,不是 13。 而且名单在增长:#18225 立卡到今天,总键数 +2、孤儿 +1。⛔ 本席不主张这个增速有代表性(两个样本),但方向是错的那一边。本席已把这条更正交叉记到 #18225。
⛔ 本席不主张这 13 个今天跑起来是红是绿 —— 那仍是 #18225 验收第 1 条的活,没人跑过。
状态
pm:dispatched→ 落地后由合入自动关卡(PR 带Fixes #16287)。本 PR 转 ready 并挂 auto-merge:不是受管面(scripts/pm/0 文件、.github/0 文件、content/docs/releases/0 文件),34 项去重检查全绿。⛔ 未绿之前不挂 —— 本席是在 NOT-GREEN 归零之后才动的手。
Generated by Claude Code
- 真实需求:自带
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actions✅ 已落地 ——
3dbb49c6bonorigin/main· 同笔摘pm:dispatched+ 清 assigneedomain:devx执行席 · 座位贴 #6023 · 落地两读,⛔ 不看merged布尔、⛔ 不看 head-sha 祖先性 · 取数时刻 2026-09-16T00:22Z读数一 · 队列分支
落地前 gh-readonly-queue/main/pr-18338-74eaab861… 在 落地后 该分支消失;队列里只剩 pr-18340-3dbb49c6b… ↑ 后者的基底就是本 PR 的 squash 提交读数二 · 重新 fetch 的
origin/main内容探针(带发火与暗对照)scripts/check-merged-result.mjs exit 0 · 35033 字节 ← 落地前 exit 128 package.json 里 'check:merged-result' 1 发火对照 scripts/check-nul-bytes.mjs exit 0 ← 仪器在响 暗对照 scripts/zz-not-real.mjs exit 128squash 提交
3dbb49c6b 2026-09-16 00:00:23 +0000 chore(devx): run a budget gate against the merged tree, where the file and its ceiling come from the same side (#18338)裁定回顾(全文在 ACCEPT 评论)
dev 那一个
open_question(探针的--self-test无人调用)本席裁 A —— 接线,一条lint.yml步骤,并并进已有的 #18224,⛔ 没新立卡:同车道、同一个文件、同一堵人工合并的墙;两张卡改同一文件的相邻两行是在制造必然冲突。#18224 正文与标题已同步。⚠️ 更正一个数字:本席此前说孤儿门禁名单是 12、本 PR 落地会变 13。重量后 落地前已是 13(总键 160 → 162,新增check:issue-citations)⇒ 落地后是 14。本席的车道是第 14 个的作者,已交叉记到 #18225。状态
卡由
Fixes #16287自动关闭(closed completed);本笔摘pm:dispatched、清 assignee,tooling · priority:p2 · domain:devx保留。
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026 - added a commit that references this issue
on Sep 28, 2026
Recording only — unassigned, no claim. Found the hard way on PR #15427 today, and generalised by that PR's own seat.
What happened, with the readings
PR #15427 added one line to
AGENTS.md. At the moment it was written the file was 1161 lines against a ceiling of 1162 — headroom 1, and the line fitted exactly.While it waited for human review, the #15379 rules-only programme compressed the same file to 1058 and, by its own shrink-only discipline, re-locked the ceiling to 1058. That is correct behaviour for a shrink-only ratchet. It also silently took back the single line of headroom the open PR had been paid from.
The PR was then approved and enqueued. It would have been dropped by the merge queue. Measured before that happened:
The PR's seat reproduced the red verbatim on the merged tree:
check-skill-line-ratchet: AGENTS.md is 1059 lines; the ratchet ceiling is 1058.mergeable_statecleangit merge-treeAll three read clean, and the merged tree violated a gate. There is no textual conflict here at all: one side deletes lines elsewhere in the file, the other adds one, and git composes them perfectly. What broke is a budget, and no textual check has a concept of one.
⛔ Note this is not the merge queue failing — the queue is the thing that would have caught it, which is exactly why it exists. The cost of finding out there is a full CI cycle plus a drop whose reason is only visible in the queue's own logs.
The class, stated so it is recognisable
Any PR that touches a ratcheted file can be textually clean and still over-budget, whenever a sibling PR compresses that file and re-anchors its ceiling in between. The longer a PR waits for review, the likelier it is: #15427 sat two days, and
AGENTS.mdmoved 103 lines under it.The same shape applies to every other budget in this repo that is pinned rather than derived — the second map in the same script (max table-row bytes, which also moved, 1081 → 768),
check:skills-token-ratchet,check:type-check-debt, and the source-token ratchets in the app repos.The mechanical answer
A merged-result probe: for each open PR touching a ratcheted path, materialise the merge with
mainand run the ratchet against that tree rather than against either side.LC_ALL=Cmatters — the second pin is in bytes, and this corpus is partly Chinese, so a character count silently under-reports by ~3x on those lines.Two placements worth weighing (⛔ not adjudicated here):
Direction 2 is the one that fits this repo's usual instinct (the change that breaks something should be the change that reports it), but it needs a live GitHub read at gate time, which several gates here deliberately avoid. Worth costing before choosing.
Related, same day, same underlying shape
--self-test, gates that it is wired, and documents nothing about its shape: 168 hand-rolled assertion helpers, and only 20 of 170 can be shown to fail on zero cases #15410 — 170 self-tests, only 20 provably fail on zero cases.content/docs; four published pages carried a stale number.All four are the same sentence: a signal that reads clean because it was never looking at the thing that broke.