Skip to content

Commit 47c1021

Browse files
os-warrenclaude
andauthored
feat(scripts): mechanize verify-lock acquisition into a capped, FIFO, self-reporting entry point (#9921)
* feat(scripts): mechanize verify-lock acquisition into a capped, FIFO, self-reporting entry point Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeA3nU1B5Q2pgxqxgUrexd * docs(agents,ci): point os-dev's lock etiquette at the entry point, and self-test it in CI Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeA3nU1B5Q2pgxqxgUrexd --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2074b26 commit 47c1021

3 files changed

Lines changed: 661 additions & 12 deletions

File tree

‎.claude/agents/os-dev.md‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ JSON,所以终报消息就是 JSON 本身,别无其它。
6666

6767
## 资源纪律 —— 并行 agents 共享同一个容器
6868

69-
1. **重活串行 —— 共享验证锁是具名约定。** 每容器一把锁,`/tmp/os-heavy-verify.lock`,包
70-
住每次 build/test:`flock -E 99 -w 540 /tmp/os-heavy-verify.lock -c '<command>'`。纪
71-
律:**释放归 `flock`**(fd 持有,命令进程树退出即释放 —— 永不手搓 lockfile);只包
72-
**命令本身**,不包你的阅读与判断;保留 **`-E 99`**,让排队超时与测试失败可区分。
73-
`-w` 要压在一次前台调用之内(本 harness 单次调用上限 10 分钟),循环重试获取 —— 盲等
74-
不能比承载它的调用活得久,为逃上限把它丢后台正是规则 7 要止的停摆。排队是常态,不是
75-
挂死。
69+
1. **重活串行 —— 共享验证锁只有一个入口。** 每次 build/test 都从这里走:
70+
`bash scripts/pm/os-verify-lock.sh -c '<command>'`(或 `-- <argv>`)。⛔ 永不手搓
71+
`flock`/lockfile —— 手写的 `-w` 正是「守约者饿死、越界者通吃」的来源(实测:同一容器
72+
五个等待者、三个越界 6 倍;越界者只凭「一直在场」就 12/12 赢走交接)。入口点保证:等待
73+
预算钉死在一次前台调用之内(更长的表达不出来)· 按到达顺序授予 · 99 仍专指「没排到」·
74+
收尾打印本次持锁时长,过长自己喊出来。只包**命令本身**,不包你的阅读与判断;结论读它
75+
印的 VERDICT 行,不读裸 `$?`。排队是常态,不是挂死。
7676
2. **压住堆**:重命令前缀 `NODE_OPTIONS=--max-old-space-size=4096`(要抬需给理由)。
7777
3. **定向,不扫全**:只 build/test 受影响的包(`pnpm --filter <pkg> …`),vitest
7878
`--maxWorkers=2`,turbo `--concurrency=2`。
@@ -85,13 +85,13 @@ JSON,所以终报消息就是 JSON 本身,别无其它。
8585
对那个 PID 操作。
8686
6. **整条流水线在前台跑。** build 与 test 都是本任务的步骤:阻塞运行、读真实输出、继续。
8787
⛔ 永不把验证挂在后台 watcher 上然后停轮(禁令与两种合法终态见「干净收尾」)。唯一合
88-
法的长等待是规则 1 的 `flock` 排队——主动、在轮内(规则 7),从不是停轮的理由。
88+
法的长等待是规则 1 的锁排队——主动、在轮内(规则 7),从不是停轮的理由。
8989
7. **排队不是停摆 —— 在轮内主动等。** 持锁的是你不拥有的进程,它的完成不会以任何方式唤
9090
醒你:⛔ 永不为「等锁」结束一轮(实测:这么做的每个 agent 都无通知地停摆,赔进一轮探
91-
活)。循环:限时获取 ⇒ 退出码 99 时把间隔花在无锁工作上(写测试、changeset、PR 正
92-
文、包内 `typecheck`)⇒ 再获取。**排队 ~20 分钟无进展 ⇒ 先看这次检查能否收窄到不必持锁
93-
(收窄要申报,见「干净收尾」);收窄不了就停下报 `blocked` 并点名持锁者**:`fuser -v /tmp/os-heavy-verify.lock`(或 `lsof`)打印其 PID 与命令 —— 一动不动
94-
的持锁者本身就是真发现。报告它;沉默是唯一错误答案。
91+
活)。循环:拿到 99 就把间隔花在无锁工作上(写测试、changeset、PR 正文、包内
92+
`typecheck`)⇒ 再跑一次。**排队 ~20 分钟无进展 ⇒ 先看这次检查能否收窄到不必持锁(收窄
93+
要申报,见「干净收尾」);收窄不了就停下报 `blocked` 并点名持锁者** —— `os-verify-lock.sh
94+
--status` 打印持锁者、已持时长与队列;一动不动的持锁者本身就是真发现。沉默是唯一错误答案。
9595

9696
## Toolchain traps(每条都至少让一个 agent 白跑一轮)
9797

‎.github/workflows/lint.yml‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,28 @@ jobs:
343343
- name: Release-rehearsal clone preflight self-test
344344
run: node scripts/pm/release-rehearsal-clone.mjs --self-test
345345

346+
# Verify-lock entry-point self-test (#9661). `scripts/pm/os-verify-lock.sh`
347+
# is the ONE way an agent takes the container's shared heavy-verify lock,
348+
# and it is the enforcement of a rule that used to live only in prose: the
349+
# acquisition budget os-dev.md declares is now unrepresentable above its
350+
# cap, grants are ordered by a ticket file, and every run reports how long
351+
# it held. Measured before it existed, in one container: five live waiters,
352+
# three of them 6x over the declared cap, and the compliant ones were the
353+
# ones not verifying — a convention whose violators win is not a convention.
354+
#
355+
# Nothing in CI *uses* the lock (GitHub runners are one job per machine),
356+
# so this step exists to keep the mechanism honest rather than to serialise
357+
# anything: 29 cases over the budget clamp, ticket liveness (dead pid,
358+
# REUSED pid, over-age), fd hygiene, exit-code passthrough, and real
359+
# multi-process contention — queue timeout, legacy free-hand coexistence in
360+
# both directions, and three staggered waiters acquiring in arrival order.
361+
# It runs entirely on a private lock under a temp dir; it never touches
362+
# /tmp/os-heavy-verify.lock, so a runner and an agent container behave the
363+
# same. Unconditional and un-`if:`-ed, like the self-tests above — an
364+
# exemption is what a self-test must not have. No network, ~15 s.
365+
- name: Verify-lock entry-point self-test
366+
run: bash scripts/pm/os-verify-lock.sh --self-test
367+
346368
# Docs/skills authoring guard (#2035 / ADR-0059): TS code blocks in
347369
# Markdown/MDX are not type-checked or ESLinted, so skills/ and
348370
# content/docs/ can drift back to teaching the bare `: Page = {}` literal

0 commit comments

Comments
 (0)