Repository navigation
[Decision] The line ratchet (check:pm-skill-ratchet): 32 of 37 files at zero headroom, so a sentence already ruled still needs a second ruling to land — keep it, let the ordering ruling carry its lines, add slack, or narrow it #23606
Description
Ruled: 6184799323 · letter B · 2026-10-15T05:07Z
Filing gate ② (a decision only the maintainer can make), filed on the maintainer's direct order (③), verbatim: 「行数门禁是否限制太严格了,开决策卡。」, given in domain:devx seat 1's session session_01ESFcvW3staenyBCGq7kcDH on 2026-10-15, about PR #23596.
Filed by domain:devx seat 1 (#6023) · huangyiirene · session_01ESFcvW3staenyBCGq7kcDH. ⛔ Not a claim. Reader who acts: the maintainer, or the director seat on the maintainer's summon. The execution lane after a ruling is domain:skills (the ratchet is the governed surface's own gate).
维护者速读
一句话问题
AI 写的指令文件(AGENTS.md、PM 技能及其 references、os-dev.md 等 37 个文件)每个都有行数上限,只降不升。其中 32 个文件余量为 0。
结果是,你已经裁定要写进去的一句话,往往还要再找你要第二句原话才能落地。今天的 #23596 就是这样:裁决 6181973363 要求加一句,os-zhuang 也已经批准,PR 仍被门禁挡住,直到你又回了一句「A 上限抬到 1117」。
背景(实测,origin/main 16abea884,2026-10-15)
- 覆盖面:
scripts/pm/check-skill-line-ratchet.mjs的CEILINGS有 37 行,32 行余量为 0。余量不为 0 的 5 个:os-dev.md2、lanes/skills.md1、lanes/director.md6、dogfood-verification/SKILL.md9、contract-review.md16。 - 近 30 天(09-15 至 10-15)的上限变动:
- 抬高 11 次,每次都要一句维护者原话;docs(agents): a test file that declares a measured budget with its class is held to that budget, not the 10 s line #23596 是第 12 次。
- 降低 3 次,另有 09-23 一次整体重构:
SKILL.md819→319,同时新建 5 个 references 文件。 - 抬高的分布:
platform-readings.md4 次,AGENTS.md3 次(1075→1099→1109→1116),SKILL.md2 次,filing-gate.md10-14 一天 2 次(58→61→64)。
- 专门为抬一次上限立过的决策卡: [PM decision] skills lane batch 7 — raise the platform-readings.md line ceiling by the measured +34 so the intake family's eight readings can land #15013(+34 行)、platform-readings.md third increment: the two post-ruling channel facts (+11), #13387's CDN-cache cause, and #13257 — needs its own ceiling ruling before dispatch #15192。
- 门禁当初的理由: 你 08-12 说「现有的项目经理 skills 应该大幅简化,只需要说原则,不需要写细节」,08-14 又说「8685 字太多了 并且综合审查一下相关的skills是不是应该压缩字数。」。当时没上限的文件一班就涨了 31%。
Governing text
.claude/skills/pm-dispatch/SKILL.md〈机械守卫索引〉 rowcheck-skill-line-ratchet.mjs: 「本文件行数只降不升(pnpm check:pm-skill-ratchet);抬上限需维护者裁决引用在 PR 正文;⛔ re-wrap 不得用作筹行,新增以删减付账;不买内容的密度修复允许」.- The ratchet's header: "RAISING one requires a maintainer ruling quoted in the raising PR's body". The header also cites the 2026-08-12 and 2026-08-14 rulings quoted above.
- [Decision] 门禁过严拖慢发版:一轮 CI 暴露全部红、成本型棘轮加容差带、门禁瘦身审计 #23177 ruling B (
6139629628), item A2′, for the siblingcheck-skills-token-ratchet.mjs: "no tolerance band … ceilings stay shrink-only and the current headroom (0 and 1 tokens) stays as it is". Item B′: an audit, due after v18nextships plus two weeks of A1, that ranks every gate family by interceptions × wall into stay, move or retire. - SKILL.md 〈升级与决策〉: 「新增门禁默认否:门禁是只减不增的零件」.
前提(各附 re-check 命令)
- 32 of 37 rows are at zero headroom on
origin/main. Re-check:It prints 32. Positive control: the same pipeline without thegit show origin/main:scripts/pm/check-skill-line-ratchet.mjs | sed -n '/^export const CEILINGS = new Map/,/^\]);/p' | grep -oE "\['[^']+', [0-9]+\]" | sed -E "s/\['([^']+)', ([0-9]+)\]/\1 \2/" | while read p c; do [ "$(git show origin/main:$p | wc -l)" -ge "$c" ] && echo "$p"; done | wc -l
whilefilter prints 37 rows, one of themAGENTS.md 1116. - 12 raises against 3 lowers in the 30 days to 2026-10-15. Re-check:
GET /repos/objectstack-ai/objectstack/commits?path=scripts/pm/check-skill-line-ratchet.mjs&since=2026-09-15 (midnight UTC, written in the API's ISO 8601 form)returns 16 commits. Diffing each commit'sCEILINGSrows gives 11 raises, 3 lowers, and the 09-23 restructuring (f151ef2c9). docs(agents): a test file that declares a measured budget with its class is held to that budget, not the 10 s line #23596 is the 12th raise, ruled at PR docs(agents): a test file that declares a measured budget with its class is held to that budget, not the 10 s line #23596 comment6184004601. Positive control:08ea7e368(filing-gate.md58 → 61) appears among the raises.
选项 × 真实代价 × 工作量
| 做什么 | 客户/团队可感知后果 | 工作量 | |
|---|---|---|---|
| A 维持现状 | 余量 0,每次加行都要你单独一句原话 | 已裁的内容常要你再答一次;席位有压力去删别的规则或压缩措辞来凑行数 | 零 |
| B 下令写入的裁决即授权其实测行数(推荐) | 一条裁决如果明确要求往受管文件写某段内容,PR 引这条裁决和实测增加的行数,同一个 PR 移动上限行,不再要第二句原话。没有裁决的增长照旧红,余量照旧为 0,不加容差 | 上限仍然逐条可追溯到裁决;只是你不再为同一件事答两次 | domain:skills · 1 PR:门禁头注与拒绝文案各一段,加 SKILL.md 守卫索引那一行改措辞(同行数,Tier S)· 不加门禁 · 无确切先例,最近的是 #23192(A2′ 执行) |
| C 加容差带 | 上限设为「落地行数 + N%」,带内增长不用裁决 | 带内会被慢慢填满,正是门禁要挡的那种累积;与 #23177 A2′ 刚裁的「不加容差带」理由相反,需要你明确推翻 | domain:skills · 1 PR:映射逻辑、自测、37 行全部重钉 |
| D 收窄覆盖面 | 把仓根的 AGENTS.md / CLAUDE.md 移出行数门禁,只管 .claude/** |
AGENTS.md 是每个 agent 每次都读的文件,当初就是从它漏进来一段 39 行条款(#9792),收窄会重开这个口子 |
1 PR,删 2 行加头注 |
| E 退役行数门禁 | 删门禁,靠评审控制篇幅 | 回到 08-14 那时的状态:没上限的文件一班涨 31% | 1 PR,Tier H(lint.yml 接线、SKILL.md 守卫索引、package.json、删脚本) |
业务含义直译
- A:「每笔支出都要老板签两次字:一次批项目,一次批钱。」
- B:「批了项目就等于批了这个项目实测要的钱;没批的支出照旧拦。」
- C:「每个部门给一笔零花钱,不用报批。」
- D/E:「取消这类文件的预算控制。」
四轴(业务立场)
- ① 项目长远合理性: 这道门禁该留,它挡的是 AI 一段一段好心地把指令写长,这个风险有实测(一班 +31%)。真正过严的是双重报批:你已经下令要写的内容,还要为它的行数再批一次。B 只去掉这一点,门禁对没有裁决的增长照样响亮拒绝。两年后的样子:指令文件的长度只随裁决移动,每一次上限变动都能追溯到一条裁决。C/D/E 都在不同程度上拆掉这道防线。
- ② 实际业务拉动: 实测有拉动。30 天抬了 12 次,次次都是已裁内容;[PM decision] skills lane batch 7 — raise the platform-readings.md line ceiling by the measured +34 so the intake family's eight readings can land #15013、platform-readings.md third increment: the two post-ruling channel facts (+11), #13387's CDN-cache cause, and #13257 — needs its own ceiling ruling before dispatch #15192 两张卡只为抬一次上限而立;今天 docs(agents): a test file that declares a measured budget with its class is held to that budget, not the 10 s line #23596 你批准之后,还被挡到你再回一句话。
- ③ 防 AI 犯错: 余量为 0 加「新增以删减付账」,会逼席位删掉别的规则或压缩已裁措辞来凑行数,规则就这样悄悄丢了含义。B 保留对没有裁决的增长的响亮拒绝,又去掉了这种压力;C 会在带内静默放行累积。
- ④ 创业阶段不扩散: B 不加门禁,只改一句规则。E 是唯一减少门禁数量的选项,但会丢掉一条实测有效的防线。按长远权重 ≥50%,仍推荐 B。
os-decision-facets
- ① 项目长远合理性:B 保留防累积的门禁,只去掉对已裁内容的二次报批;C/D/E 削弱或拆除防线。
- ② 实际业务拉动:30 天抬上限 12 次,全部是已裁内容;docs(agents): a test file that declares a measured budget with its class is held to that budget, not the 10 s line #23596 批准后仍被挡,直到第二句原话。
- ③ 防 AI 犯错:B 对没有裁决的增长照旧响亮拒绝,并去掉「删规则凑行数」的压力;C 的容差带会静默放行累积。
- ④ 创业阶段不扩散:B 零新增门禁、只改一句规则;E 是唯一减少门禁的选项,但代价是丢掉实测有效的防线。
Prior rulings read: line ratchet,skill-line-ratchet,headroom,行数 → 0 hits (check-prior-rulings at 16abea88); #23177 ruling B items A2′ and B′ (6139629628), read in full; the ratchet header's 2026-08-12 and 2026-08-14 rulings; thread: none (new card); repo: objectstack-ai/objectstack
推荐 B,回退 A,置信缺口
- 推荐 B。 只看①就选 B:它在不削弱防线的前提下,去掉了对已裁内容的二次报批。②③④ 不翻转。
- 回退 A, 并把这道门禁交给 [Decision] 门禁过严拖慢发版:一轮 CI 暴露全部红、成本型棘轮加容差带、门禁瘦身审计 #23177 B′ 审计统一排序,看拦截次数 × 耗时,决定留、挪还是退役。
- 置信缺口:
- 测不到这道门禁真正的收益:有多少 PR 因为它改成删内容抵行数,有多少新增因此被压短。git 历史里只看得到上限变动,看不到被它改写过的 PR。
- 也测不到有多少次席位为了凑行数而删减或压缩了已裁措辞。
裁后执行段
- 裁 B:
domain:skills车道一张卡。- 门禁头注加一段:裁决明确要求写入的内容,PR 引裁决 ID 与实测行数增量,即构成抬上限的授权。
- 拒绝文案同步。
- SKILL.md 守卫索引那一行改措辞,同行数,Tier S。
- 已经落地的上限不回改。
- 裁 A: 本卡关闭,[Decision] 门禁过严拖慢发版:一轮 CI 暴露全部红、成本型棘轮加容差带、门禁瘦身审计 #23177 B′ 审计时把本门禁列入排序。
- 裁 C / D / E:
domain:skills车道一张卡,按上表执行。裁 C 等于明确推翻 [Decision] 门禁过严拖慢发版:一轮 CI 暴露全部红、成本型棘轮加容差带、门禁瘦身审计 #23177 A2′ 的理由,执行卡需引这一条。
Related
- PR docs(agents): a test file that declares a measured budget with its class is held to that budget, not the 10 s line #23596: the instance that raised the question.
- [Decision] The 10 s per-file test budget (#22949 ruling E item 3) and gate self-tests that spawn the real gate once per one-cause fixture: an exemption class, or a measured per-file ceiling beside the window's readings #23534: its card, closed.
- [PM decision] skills lane batch 7 — raise the platform-readings.md line ceiling by the measured +34 so the intake family's eight readings can land #15013 and platform-readings.md third increment: the two post-ruling channel facts (+11), #13387's CDN-cache cause, and #13257 — needs its own ceiling ruling before dispatch #15192: per-instance raise decisions.
- ratchet: AGENTS.md is the only agent-instruction file with no line ceiling — the leak the 39-line clause came through #9792 and finding: CLAUDE.md carries no line-ratchet ceiling, while AGENTS.md does — same read path, same governance #9965: the coverage findings that added
AGENTS.mdandCLAUDE.mdto the ratchet. - [Decision] 门禁过严拖慢发版:一轮 CI 暴露全部红、成本型棘轮加容差带、门禁瘦身审计 #23177 and ci(skills-ratchet): exclude the whole release-bot
version:stamp line from the token count and re-pin the ceilings so headroom stays 0 and 1 (#23177 ruling B, item A2′) #23192: the sibling token ratchet's no-band ruling and its execution.
Dedupe: MCP search_issues on objectstack-ai/objectstack, closed included, query line ratchet ceiling too strict headroom zero raise requires maintainer ruling skill line count: 9 hits, all read. None decides the ratchet's strictness. The nearest are #15013 and #15192 (closed, per-instance raises), #9792 and #9965 (closed, coverage), and #23192 (closed, A2′ execution).
Activity
objectstack-fleet commentedon Oct 15, 2026
席位意见(增量)· director seat (summon #37 continuation 2,
session_01LqNgdPZB2Jnr5HpGbaqLeB), read as batch #348 item 2, 2026-10-15T04:48ZPremises re-run on
origin/main8d05456cb: the card's pipeline prints 32 rows at zero headroom of 37 (P1 holds); the instance, PR #23596 (theAGENTS.mdline ruled by 6181973363 on #23534), is merged as93709a212after the maintainer's second word raised the ceiling; three files this batch's own rulings touch sit at their ceilings (SKILL.md319/319,execution-duties.md183/183,os-dev.md400/402), so B's first cases are in this batch. Prior rulings (check-prior-rulings --card 23606): 398 candidates, none on the ratchet; #23177 ruling B items A2′ (no tolerance band) and B′ (the gate audit) read as the card cites them. P2 (12 raises against 3 lowers in 30 days) is not re-counted here.Facets: ① agree (keep the gate; remove the second ruling for content the first ruling ordered) · ② agree · ③ agree · ④ agree.
Recommend B, fallback A, with 口径 for the executor:
SKILL.mdguard-index row rewords at equal line count; landed ceilings are not revisited.Workload of the letter (the card's column):
domain:skills· 1 Tier S PR (the ratchet header and refusal text, theSKILL.mdindex row at equal length) · no exact precedent (#23192, A2′'s execution, is the nearest). A = 0; C/D/E as the table.自检:只看①选 B;②③④ 是否翻转:否。
objectstack-fleet commentedon Oct 15, 2026
Decision-box entry: passes ·
priority:p2·domain:skills·area:devpathadded · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-15T04:59ZEntry check on the card body. These are all present:
It passes.
Labels added:
priority:p2+domain:skills+area:devpath.objectstack-fleet commentedon Oct 15, 2026
Ruling: batch #348 item 2 · letter B · maintainer 「同意」 2026-10-15T05:00Z
Director seat, summon #37 (continuation 2),
session_01LqNgdPZB2Jnr5HpGbaqLeB, on the card's analysis (recommendation B, fallback A; filed on the maintainer's 「行数门禁是否限制太严格了,开决策卡。」) and the seat's delta 6184660794; the maintainer's 「同意」 takes the recommendation.What the ruling binds (letter B):
CEILINGSrow in the same PR by at most that delta. No second word from the maintainer is needed.SKILL.mdguard-index row rewords at equal line count; ceilings already landed are not revisited.execution-duties.md, [Decision] Three spec contract dev agents in one container queued ~70 min each on the shared verify lock: leave packagetest:repoto CI, and send build-heavy cards to cloud sessions? #23607's lines inos-dev.mdandexecution-duties.md, [Decision] contract review of a mixed diff: does one governed path send the whole PR to CONTRACT_REVIEW_TIER, or only the governed hunks? #23578's line incontract-review.md): each such PR quotes its ruling and its delta.Workload of the letter:
domain:skills· 1 Tier S PR (the ratchet header and refusal text; theSKILL.mdindex row at equal length) · no exact precedent (#23192, A2′'s execution, is the nearest).Execution: this card is the execution card:
needs-user-decisionremoved,pm:queue,domain:skillsandpriority:p2added in this act; the body's first line carriesRuled:. The card closes on the ratchet PR's landing.objectstack-fleet commentedon Oct 15, 2026
Claim: PM loop round 1
Session:
session_01GjUZrCo7Yi58T4vPXqx88eAccount:
os-sales(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-23606-ratchet-ruled-raiseWorktree:
objectstack-issue-23606Domain:
domain:skillsSeat:
domain:skills#1File surface:
scripts/pm/check-skill-line-ratchet.mjs(the header docblock's 「ratchet discipline」 paragraph and the refusal/remedy text a red verdict prints, plus the self-test cases that pin that text; ⛔ noCEILINGSrow — PR #23660 moves theexecution-duties.mdrow, #23607 will move two more) ·.claude/skills/pm-dispatch/SKILL.md(the 〈机械守卫索引〉 row for the ratchet, reworded at equal line count and within the row-width pin of 342 bytes) (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: fable (CONTRACT_REVIEW_TIER) — dispatch-gates.mjs --tier --repo objectstack-ai/objectstack at c5dd7fce3 reads "Model tier — MANDATORY: … .claude/skills/pm-dispatch/SKILL.md ⇢ clause ① of the model-tiering ruling (narrowed to protocol semantics, 2026-08-20): the PM dispatch skill MAIN file is the lane's own operating protocol"; the one-line mechanical exit is not taken: the lane charter holds the pm-dispatch root at the contract-review tier (lanes/skills.md 「pm-dispatch 根恒契约复审档」), and two rules in conflict are read by the stricterClause-②: no
Responsibility:
n/a — not a defect cardThread-read: 6184799323
Serial constraints cleared:
check-skill-line-ratchet.mjs is shared with PR #23660 (#23579, this lane, in its landing window: the execution-duties.md CEILINGS row and its comment block) and later with #23607 (queued): this card edits the header docblock, the refusal text and the self-test only — disjoint regions; the dev merges origin/main before opening its PR and again if PR #23660 lands first; SKILL.md has no other claim; under the maintainer's 「并发保持1」 this is the lane's only dev in flightRuling-ref: 6184799323
Claimed 2026-10-15T11:13Z with
origin/mainat1ced0f82b(the header still reads 「RAISING one requires a maintainer ruling quoted in the raising PR's body」 at line 66, the control). The dev leaves no second claim: this comment is its identity, and it checks that the newestClaim:here names its branch before any edit.objectstack-fleet commentedon Oct 15, 2026
Dispatch order — posted 2026-10-15T11:16Z by the claiming seat (
session_01GjUZrCo7Yi58T4vPXqx88e, os-sales); the same text is the dev's prompt,mode:subagent, model tier fable (CONTRACT_REVIEW_TIER, the SKILL.md path mandate).Dispatch — issue #23606 (objectstack-ai/objectstack) ·
domain:skills· PMsession_01GjUZrCo7Yi58T4vPXqx88e(os-sales)You are the
os-devdeveloper for exactly one card: objectstack-ai/objectstack issue #23606. Read the card's body and EVERY comment yourself (the director's delta, triage's entry, the ruling, the seat's claim) and check the body is complete before you start. The PM'sClaim:comment on the card (id 6190726655) is your identity: itsBranch:isclaude/issue-23606-ratchet-ruled-raise, its worktreeobjectstack-issue-23606. Verify the newestClaim:on the card names that branch before any edit; on a mismatch stop and report. ⛔ Leave no second claim, ⛔ never write the card's assignee; the PR's assignee isos-sales(pr_createwithassignees: ["os-sales"]). Your standard duties (worktree-first, push the empty branch first, the shared verify lock, the report shape, the sanitizer rules) live in.claude/agents/os-dev.mdandAGENTS.md; this order carries only the increments. The repository checkout is/home/user/objectstack(shared, ⛔ never edit it; your worktree goes beside it). Run everything in the foreground; a round ends only with the report.1. Ruling — not re-decidable (
Ruling-ref: 6184799323, letter B, the maintainer's 「同意」 2026-10-15)Quoted from the ruling of record on the card (comment 6184799323):
Deliverable: ONE draft PR to
main, first body lineFixes #23606, editing exactly these surfaces:scripts/pm/check-skill-line-ratchet.mjs—(a) the header docblock's 「ratchet discipline」 bullet (today lines 66–70: 「RAISING one requires a maintainer ruling quoted in the raising PR's body (the same evidence bar as Guardrails'
.claude/tooling exception). A protocol change that would cross a ceiling pays its way by moving narrative out (SKILL.md → references/) or compressing in place, instead of raising the roof.」) restated to the ruled form: a ruling of record that ORDERS text into a ratcheted file is the raise's authorization — the raising PR quotes that ruling comment's id and the measured line delta in its body and moves theCEILINGSrow in the same PR by at most that delta, no second word needed; a raise quoting no ruling id stays red; ⛔ no tolerance band; 「新增以删减付账」 for every line no ruling ordered; landed ceilings are not revisited. Keep the rest of the discipline (lowering always legitimate, the small headroom, the cross-file move) as it is. The header may cite the ruling record id 6184799323 as provenance (the file already cites rulings this way).(b) the red verdict's remedy sentence in
verdict()(today line 2114: 「Raising a ceiling requires a maintainer ruling quoted in the PR.」) and the three cross-file-move refusals that send an author to 「the ordinary way — a maintainer ruling quoted in the raising PR」 (today lines 2205, 2236, 2273): each names the form — the ordering ruling of record's comment id and the measured delta quoted in the raising PR's body, the row moved by at most that delta.(c) the self-test cases that pin those sentences (for example line 3172,
msg.includes('maintainer ruling quoted in the raising PR'), and the 「red message names the remedy」 cases): update the pinned substrings to the new wording — ⛔ never weaken or delete a case; the battery floors stay;node scripts/pm/check-skill-line-ratchet.mjs --self-testmust pass (157 cases onmaintoday).⛔ No
CEILINGSrow moves in this PR (none is ordered; PR pm-dispatch execution-duties: a split-off off-lane card does not inherit the parent's domain; ceiling 183 → 185 by ruling #23660, in its landing window, moves theexecution-duties.mdrow; [Decision] Three spec contract dev agents in one container queued ~70 min each on the shared verify lock: leave packagetest:repoto CI, and send build-heavy cards to cloud sessions? #23607 will move two more). ⛔ No new mechanical check: item 3 says the script cannot read rulings and the readers are the seat record and the queue guard's reader; 「新增门禁默认否」..claude/skills/pm-dispatch/SKILL.md— the 〈机械守卫索引〉 row for the ratchet (today line 291, 240 bytes: 「|scripts/pm/check-skill-line-ratchet.mjs| 本文件行数只降不升(pnpm check:pm-skill-ratchet);抬上限需维护者裁决引用在 PR 正文;⛔ re-wrap 不得用作筹行,新增以删减付账;不买内容的密度修复允许 |」): reword the 「抬上限需维护者裁决引用在 PR 正文」 clause to the ruled form (a ruling of record ordering the text + the measured delta quoted in the PR body authorizes the raise; no ruling id ⇒ red), at EQUAL line count (319/319 — the file has headroom 0 and no raise is ordered for it) and within the table-row width pin of 342 bytes; the rest of the row stays. ⛔ No issue number in the row (check:pm-skill-id-lintwalks this file); 「裁决记录」 or a comment id is fine.2. PM mechanism assumptions — measure before you build; falsify and report where wrong
origin/main1ced0f82b: the header bullet at lines 66–70; the red remedy at 2111–2114; the three cross-file refusals at 2205, 2236, 2273; the self-test pin at 3172;MAX_LINE_BYTES = 120(2282) andMAX_TABLE_ROW_BYTESforSKILL.md342 (the row today is 240 bytes);SKILL.md319 lines at ceiling 319. Line numbers are clues; re-find by text.scripts/pm/check-skill-line-ratchet.mjs:8d05456cb(PR docs(agents): a test file that declares a measured budget with its class is held to that budget, not the 10 s line #23596) moved theAGENTS.mdrow this morning, and PR pm-dispatch execution-duties: a split-off off-lane card does not inherit the parent's domain; ceiling 183 → 185 by ruling #23660 ([Decision] A card triaged to one lane carries an item that lands in another (#23513: an engine card with a skills/** item) — who splits it, and when #23579, this lane) is landing with theexecution-duties.mdrow 183 → 185 plus a comment block above it. Work from merged code: mergeorigin/maininto your branch before opening the PR, and once more if PR pm-dispatch execution-duties: a split-off off-lane card does not inherit the parent's domain; ceiling 183 → 185 by ruling #23660 merges while you work; its hunk is aCEILINGSrow, yours are the header, the remedy strings and the self-test — disjoint, a clean textual merge expected; a conflict is reported, ⛔ not resolved by dropping either side.pnpm check:pm-skill-ratchetreadsSKILL.md's line count and its widest table row;pnpm check:pm-skill-id-lintwalks.claude/skills/**andos-dev.md;pnpm check:skill-frame-synccompares the four-axis block (do not touch it).red message names the remedypinsreferences/; the move refusals pinRULING_CITATIONand the 「ordinary path」 sentence); nothing outside the file pins them — verify withgit grep -n "maintainer ruling quoted" -- scripts packages .claudeand report the hit list.3. PM suggested route — optional; measurement wins
CEILINGSrow in the same PR by at most that delta — no second word from the maintainer. A raise quoting no ruling id stays RED; there is no tolerance band; every line no ruling ordered is still paid for by deletion (「新增以删减付账」); landed ceilings are not revisited. A protocol change with no ruling behind it pays its way by moving narrative out (SKILL.md → references/) or compressing in place.」SKILL.mdrow clause, a possible shape (equal line count; count bytes): 「抬上限 = 下令写入的裁决记录 id + 实测行数增量引在 PR 正文,同 PR 移上限行;无裁决 id 即红」.4. Verification you owe (the derived gate families below are a clue, not the spec)
Derived at
c5dd7fce3bynode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack scripts/pm/check-skill-line-ratchet.mjs .claude/skills/pm-dispatch/SKILL.md(39 commands). After your FINAL commit re-derive with no paths (node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack), run the local subset, capture each exit code before any pipe, reconcile with--ran, and quotegit rev-parse --short HEADof that run in the report and the PR body. CI runs the full farm; cite the PR's check-runs (name + conclusion) for every family CI runs.Plus the edited script's own suite:
node scripts/pm/check-skill-line-ratchet.mjs --self-testand the plain runnode scripts/pm/check-skill-line-ratchet.mjs. Heavy runs go throughbash scripts/pm/os-verify-lock.sh -c '…';check:*gates do not.pnpm check:pm-dispatch-gatesis a long battery:nohup … > LOG 2>&1 &thentail --pid, as os-dev.md says.5. PR body and labels
Fixes #23606; then the lineClause-②: noat line start (copied from the claim; no arm).## 维护者速读(草稿)section (Chinese, business angle; five fixed parts: 改了什么 / 为什么改 / 风险与代价(含回滚) / 席位意见(留空) / 你要做的). Quote ruling 6184799323 letter B..claude/**,scripts/pm/**): write no changeset and add theskip-changesetlabel throughscripts/pm/label-write.mjs(labels only)..claude/**, Tier S): push, open the draft PR, deliver the report and STOP — the seat lands it on its contract-review PASS. ⛔ Never flip it out of draft, never arm auto-merge.6. Writes
Writes:REST proxy only, throughscripts/pm/tools (git pushis not a REST write). Budget:git push(as needed) ·pr_createonce (draft,assignees: ["os-sales"]) ·label-writeonce (skip-changeset) ·post-stamped --comment=23606once (theos-dev-reportcomment). Reportapi_writes(count + endpoints) andmcp_calls(count + tool names; a write tool in the list refuses the report). Reads of the card and thread: the public card page's embedded payload or one REST read, as os-dev.md says.7. Report
Deliver the JSON report twice as
.claude/agents/os-dev.mdspecifies: first as a comment on #23606 whose first line is the bare textos-dev-report, then as your final message (the JSON alone, no surrounding prose).premise_still_valid: falsewithpr: nullis a first-class delivery if the header and remedy already read the ruled form onorigin/main.8. The four-axis decision frame (verbatim copy of
.claude/skills/pm-dispatch/SKILL.mdlines 241–261 at7b3d5585c, md5abff5f852c8fd09b79ec0623439aa4f0; the byte-exact copy is also at/tmp/claude-0/-home-user/876b3822-3359-5422-9c06-6ea8906efb25/scratchpad/frame.md) — use it only if aneeds_decisionarises; ⛔ keep no copy in the repo每个方案必须沿四条固定评估轴分析,这是决策分析的核心原则,不是可选项:
还是投机性能力面?判据要求实测(谁在写这个键、谁在读、
示例应用与真实部署的用法),「读起来像有用」不作数。这条轴会改变结论,不是陪衬。
contract-first),临时补丁式选项要明说长期代价。
契约收紧(严格 schema、publish 时响亮拒绝)优于消费端宽容(
??回退、静默容错)——宽容恰是 AI 批量犯错被掩盖的温床;声明即强制,绝不让 AI 声明一个运行时不兑现的能力。
从紧,无拉动的声明面按 implementation-first 处置,已发布零消费能力不因沉没成本豁免。
过渡也从紧 —— 创业阶段不渐进:废弃别名/拼写与能力退役默认立即退休,无分阶段
窗口、无双拼写宽限;staged 仅凭具名外部用户证据方可荐。新增门禁默认否:门禁是只减
不增的零件,例外只有维护者点名;荐新增门禁须引其点名原话,否则荐「不加」。
基本裁决原则:spec 声明 > 实现 > 文档面;声明而未兑现是实现缺口,补实现或退役,
⛔ 不在消费端收窄;未声明键随实现,文档随之。「声明即强制」只及 spec 与元数据契约、
运行时能力,⛔ 不及 AGENTS.md 这类给 agent 读的约定 —— 那些的读者是 agent,不是门禁。
推荐意见必须基于这四条轴给出理由;四轴冲突时如实呈现权衡,
交维护者拍板。
objectstack-fleet commentedon Oct 15, 2026
already claimed — yielding · seat
domain:skills#2,session_01VqGhCg9wdsBXPz54uAEWg7(os-elon-musk) · 2026-10-15T11:24ZSeat 1's
Claim:6190726655 (session_01GjUZrCo7Yi58T4vPXqx88e, os-sales) is the earlier one and stands; ⛔ not a claim.label-writeaddedos-elon-muskas a second assignee at 2026-10-15T11:21Z (the label set was alreadypm:dispatchedwithoutpm:queue, so no label changed). It was taken off again, and the read-back showsos-salesalone. Seat 2 posted no claim and pushed no branch on this card, and it sent no dispatch.os-salesas the assignee, and the write was not gated on it. The error is seat 2's.SKILL.mdL291, the ratchet's guard-index row, is 241 bytes onorigin/main1ced0f82b.CEILINGSmap region.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{ "issue": 23606, "status": "done", "branch": "claude/issue-23606-ratchet-ruled-raise", "pr": "https://github.com/objectstack-ai/objectstack/pull/23668", "session": "session_01GjUZrCo7Yi58T4vPXqx88e — this run's harness-stamped id (subagent = parent's; the relay's route reader derived the same id from the container's CLAUDE_CODE_REMOTE_SESSION_ID)", "premise_still_valid": true, "summary": "Premise checked at origin/main 1ced0f82b: line 66 of scripts/pm/check-skill-line-ratchet.mjs still read 「RAISING one requires a maintainer ruling quoted in the raising PR's body」 (the claim's control), so the card's work was live. Restated the per-file line ratchet's raise authorization to ruling record 6184799323 letter B: the header 「ratchet discipline」 bullet, verdict()'s red remedy and the three cross-file-move refusals (two in crossFileMoveVerdict, one in crossFileMoveTotalVerdict) now name the form — the ordering ruling of record's comment id and the measured line delta quoted in the raising PR's body, the CEILINGS row moved in the same PR by at most that delta; a raise quoting no ruling id stays red; no tolerance band; 「新增以删减付账」 for every unruled line; landed ceilings not revisited. The self-test re-pins the one old-wording case and adds seven cases (the form, the delta bound and the no-ruling-id/no-band sentence in verdict(); the form in each move refusal; a negative pin that none of the four line-ceiling refusals still says 「maintainer ruling quoted」) — 164 cases, roster floor 157 → 164, nothing weakened or deleted. The pm-dispatch SKILL.md 〈机械守卫索引〉 row rewords at equal line count (319/319; the row 240 → 336 bytes under the 342-byte table-row pin; no issue number in it). No CEILINGS row moved, no new mechanical check. origin/main moved mid-work (PR #23660 landed as 881eeff31: the execution-duties.md row 183 → 185 plus its comment block, which itself quotes ruling record 6184799323 as the raise's authorization); merged as 1bcccbaf9 — clean, disjoint; the branch's delta vs origin/main is exactly the two files. Draft PR #23668 is open on main with first line Fixes #23606 and Clause-②: no, assignee os-sales, labels skip-changeset (mine) + documentation and size/s (set by other actors, left as found); Tier S (.claude/**): pushed, opened, reported, stopped — not readied, no auto-merge.", "tests": "Edited script's own suite at 1bcccbaf9: `node scripts/pm/check-skill-line-ratchet.mjs --self-test` → exit 0, 「✓ check-skill-line-ratchet self-test: 164 cases pass.」 (the same command on the unmodified base 1ced0f82b → exit 0, 157 cases); plain `node scripts/pm/check-skill-line-ratchet.mjs` → exit 0, 「.claude/skills/pm-dispatch/SKILL.md is 319 lines (ceiling 319; headroom 0)」, 「widest table row is 342 bytes (pin 342; headroom 0)」 (the widest row is a different row; the reworded row is 336 bytes), 「references/execution-duties.md is 185 lines (ceiling 185; headroom 0)」 after the merge. Red-then-green without an ablation (scripts are not ablated, and there is no dist/ in this diff): with the four strings changed and the pins untouched, the self-test exited 1 with exactly one failure — 「✗ ...and sends the author to the ordinary path rather than to a bigger declaration」, the old pin — and with the pins updated it is green at 164. Assumption (d) measured: `git grep -n 'maintainer ruling quoted' -- scripts packages .claude` on the branch hits, inside the file, only the RULING_CITATION docblock, the table-row-bytes pin's docblock and refusal, and the two new negative self-test pins; outside the file only unrelated prose (scripts/pm/check-half-states.mjs:338, scripts/pm/dispatch-gates.data.mjs:1161, packages/metadata-core/CHANGELOG.md:614) — nothing outside the file pins the ratchet's remedy strings.", "gates": "Local subset derived at 1bcccbaf9 by `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths; 39 commands, byte-identical to the derivation at e8ae56f27; the tool's first stderr line named objectstack-ai/objectstack at 1bcccbaf9 and the --repo check against origin held). All 39 ran at 1bcccbaf9, each exit captured before any pipe (`bash -c cmd > log 2>&1; EXIT=$?`). 38 quick families exit 0: check-ci-filter-parity; check-closing-keyword-parity (+ --self-test); check-comment-mask-corpus; check-declaration-mirrors (+ --self-test); check-scripts-symbol-anchors (+ --self-test); check-self-test-wired (+ --self-test); check-self-test-workflow-commands (+ --self-test); check-whole-set-label-write (+ --self-test); pm/bare-root-worklist --self-test; pm/check-governed-queue-guard --self-test; pm/check-harness-current --self-test; @objectstack/lint check:doc-formula-expressions; check:agent-test-spelling; bash32-floor; cli-command-ids; cross-package-test-inputs; doc-authoring; driver-memory-census; entry-guard; gitlink-declared; nul-bytes; parse-guard; pm-expected-skips; pm-governed-merges; pm-governed-prose; pm-skill-id-lint 「87 file(s) clean」; pm-skill-ratchet; pnpm-filter-targets; ratchet-remedy-authority 「275 scripts swept; 14 mark, 5 turn down, 256 hand out no ratchet-expanding remedy」 (this file stays `excluded`); refd-timer-probe; skill-frame-sync; watch-hint-literal. `pnpm check:pm-dispatch-gates` under nohup with its exit written to a file → EXIT=0, 「✓ dispatch-gates self-test (fast tier): 1884 cases pass; 6 slow section(s) deferred.」 (269.6 s on the shared box). check:doc-formula-expressions first exited 3 at e8ae56f27 — PREREQUISITE NOT MET (@objectstack/formula and @objectstack/lint unbuilt), not a measurement; `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2` ran under os-verify-lock.sh (OS_VERIFY_LOCK_SLOT=issue-23606; VERDICT command-exit 0; 4 tasks, all cached) and the rerun exits 0. `--ran ran.list --repo objectstack-ai/objectstack` → exit 0, 「✓ dispatch-gates --ran: 39 derived famil(ies) accounted for — 39 run, 0 NOT-MEASURED (a DERIVED zero — all 39 recorded an exit code and none of them is 3)」, 0 UNRUN. Local-only families check:dev-prereqs / check:skill-frame-freshness: not derived and not owed (no packages/spec build, no four-axis file touched). CI — PR #23668 check-runs at 1bcccbaf9, read after the label write (40 runs): success — Governed Surface Queue Guard, Check Changeset, The card this PR closes must claim this branch, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, Part-of PR must not also close its card, Check PR Size, Auto Label, Check Documentation Links, Dogfood Regression Gate, filter, Lint · scoped · query-options erasure, Type Check · workspace, Type Check · debt ledger, Test Core 3/6 4/6 5/6 6/6; in_progress — Lint · ESLint, Lint · PM dispatch-gates, Lint · repo & tooling gates, Lint · docs & code guards, Lint · CI release & engine gates, Lint · scoped · tooling self-tests, Lint · scoped · slot lookup & corpus, Type Check · source gates, Type Check · consumer gates, Test Core 1/6 2/6; skipped by path filter — Build Core, Build Docs, Console Pin Gate, Dogfood Verify CLI, Temporal Conformance (live PG + MySQL), Packed-tarball smoke, the matrix-template Dogfood shard. The required Lint & Repo Gates / TypeScript Type Check / Test Core contexts are still converging; in_progress is the honest value and was not waited on.", "mcp_calls": "0 — no MCP GitHub tool was called. The card was read from the public issue page's embedded payload (issueViewerRoute; backTimelineItems hasNextPage=false, 14 items, the newest Claim: names this branch); the PR, its labels and its check-runs were read with `gh api` GET calls (reads, not writes).", "api_writes": "4 — every write through scripts/pm/ over the fleet-write relay (transport dispatch, as objectstack-fleet[bot]): POST /repos/objectstack-ai/objectstack/pulls (pr_create, draft forced, relay run 38730197916; read-back 10413 bytes sent = 10413 stored) and POST /repos/objectstack-ai/objectstack/issues/23668/assignees (the same pr_create action's assignee leg; os-sales); POST /repos/objectstack-ai/objectstack/issues/23668/labels (label-write --add skip-changeset, relay run 38730334059; read-back matches: documentation, size/s, skip-changeset); POST /repos/objectstack-ai/objectstack/issues/23606/comments (post-stamped --comment=23606, this os-dev-report). git push ×3 (the empty-branch probe, e8ae56f27, 1bcccbaf9) are not REST writes. No PATCH, PUT or DELETE; no bare curl/gh write.", "deviations": "(1) The harness's built-in removal check refused two commands: a gate-runner line that carried `rm -f` of a not-yet-existing ran-list (reissued without the removal to fresh filenames; results unaffected) and the deletion of a stray 19-byte file my mis-backgrounded nohup line wrote at the filesystem root, /battery2.pid (content BATTERY2_PID=22880) — not removed; it needs a person's hand. (2) The first pm-dispatch-gates battery run's exit code was not captured (plain nohup, verdict line only); it was rerun twice with the exit written to a file (EXIT=0 at e8ae56f27 and at 1bcccbaf9) and only those are cited. (3) The harness attribution reminder names a model in its Co-Authored-By form; both commits carry AGENTS.md's model-free pair instead (the pre-push hook accepted them); no model identifier in the PR, commits or comments. (4) The header's restatement of ruling item 3 reads 「the quote is checked by the seat's contract-review record and by the queue guard's reader, never here」: check-governed-queue-guard.mjs has no ratchet reader, so the sentence attributes the check to its readers rather than to a mechanism. (5) The SKILL.md row's reworded clause is the PM's suggested shape in substance, measured rather than copied: 「抬上限凭下令写入的裁决记录:其评论 id 与实测行数增量引在 PR 正文,同 PR 移上限行至多增量;无裁决 id 即红」.", "open_questions": [], "out_of_scope_findings": [ "carrier: the seat's contract review of PR #23668 (a one-line touch if wanted) · noted, not filed — in the same file, two docblocks still spell the ordinary raise in the older, less specific words: the RULING_CITATION docblock (「the header's escape hatch (a maintainer ruling quoted in the raising PR)」) and the header section 「A move's raise and an ORDINARY ruled raise are separate quantities」 (「the header's own exit, a ruling quoted in the raising PR」). Both defer to the restated header bullet and are not false under the ruled form (the ordering ruling IS a maintainer ruling quoted in the raising PR); outside the claimed surface (header bullet, red remedy, refusals, self-test), so untouched. Dedupe words: RULING_CITATION docblock, ordinary ruled raise, header's escape hatch, check-skill-line-ratchet.", "carrier: none · noted, not filed — MAX_TABLE_ROW_BYTES (the per-file widest-table-row byte pin) keeps 「raising a pin requires a maintainer ruling quoted in the PR」 in its docblock and its refusal. It is a byte pin, not a line ceiling; ruling 6184799323 speaks of measured lines and the CEILINGS row, so whether the ruled form extends to the byte pin is a question for the seat, not a finding. Dedupe words: MAX_TABLE_ROW_BYTES, table-row pin, byte pin ruling, widest table row.", "carrier: none · noted, not filed — scripts/check-ratchet-remedy-authority.mjs's CONTROL entry for pm/check-skill-line-ratchet.mjs (expect excluded; 「its ceiling-raise remedy already names the authority it requires」) still reads true after the rewording: the authority is now the ordering ruling of record and none of the four messages uses an offer verb of that gate's grammar — measured, gate exit 0, verdict unchanged. Recorded so the seat need not re-measure it. Dedupe words: ratchet-remedy-authority, CONTROL excluded, offer verb." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
ACCEPT → PR #23668 comment 6191600702 (seat record,
domain:skills#1,session_01GjUZrCo7Yi58T4vPXqx88e); the at-tier contract review of record is PR #23668 comment 6191503551 (PASS on head1bcccbaf9). Tier S landing by the seat follows:pr_ready,automerge_enable, the queue. 2026-10-15T12:04Zobjectstack-fleet commentedon Oct 15, 2026
Landed — PR #23668 MERGED as
5a3315490(squash; the queue's merge,auto_merge_enabledby the seat at 2026-10-15T12:06Z,added_to_merge_queueat 2026-10-15T12:08Z, merged at 2026-10-15T12:24Z) · seatdomain:skills#1·session_01GjUZrCo7Yi58T4vPXqx88e(os-sales) · 2026-10-15T12:27Zgit ls-remote origin refs/heads/gh-readonly-queue/main/pr-23668-*git merge-base --is-ancestor 881eeff31 origin/main(control, a known main commit)git merge-base --is-ancestor 1bcccbaf9 origin/main(the PR head)git log -1 origin/main -- .claude/skills/pm-dispatch/SKILL.md5a3315490 feat(pm): line ratchet — a raise is authorized by the ordering ruling of record (id + measured delta in the PR body) (#23668)git show origin/main:.claude/skills/pm-dispatch/SKILL.mdline countcompletedbyFixesat the mergedomain:skills, open)pm:blocked) · #23607, #23615, #23662 (pm:dispatched, seat 2, os-elon-musk) · #22060, #17161 (tracking) · #19287 (seat 2) — no stray closurecheck-expected-skips.mjs --pr 236685a3315490;check-harness-current.mjsCURRENT; mirror branch pushedState change:
pm:dispatchedremoved in this act (domain:skills,area:devpath,priority:p2stay); the PR subscription ended at the merge. From this merge the line ratchet's header and refusal text name the ruled raise form: the ordering ruling of record's comment id and the measured line delta quoted in the raising PR's body, theCEILINGSrow moved in the same PR by at most that delta; a raise quoting no ruling id stays red.