Repository navigation
Commit 7189fb2
chore(pm): write-pace rule ② default 40 → 80 writes per token-hour (#31363)
Fixes #31302
Clause-②: no
Metadata-protocol: none
Skills-docs: none — internal PM tooling under `scripts/pm/`; nothing a
metadata author writes moves, and no `skills/**` or docs page states the
write budget
## 维护者速读
- 改了什么:车队写入节流 `write-pace.mjs` 的每令牌每小时写入上限默认值 40 → 80;脚本头部补上裁决原文与残余风险说明。
- 为什么改:席位与它派出的开发共用同一令牌、同一份计数,席位临时用测试专用变量提到 80 后开发仍按 40
被拒;改默认值让所有进程自动一致(按「写入配额临时增加到80」与「同意」方案 C)。
- 风险与回滚:防封靠的最小间隔、全队单写租约、批量间隔、遇平台退避即停四条都没动;残余风险是同一令牌跑多个容器时每个容器各算
80,会叠加。回滚 = 把常量改回 40 并同步自测里那一处字面钉。
- 先看:`scripts/pm/write-pace.mjs` —— 常量那一行、头部「Why ② is 80」一节、自测 limits
组新增的字面钉。
- 两分钟验证:`node scripts/pm/write-pace.mjs --self-test`,预期 `✓ write-pace
self-test: 119 cases pass across 12 batteries`;`node
scripts/pm/write-pace.mjs --status` 显示 `budget : N of 80`。
- 需要你做的:无,席位落地。
## What changes
- `scripts/pm/write-pace.mjs`: `DEFAULT_HOURLY_MAX` 40 → 80. Rule ②
header text now reads 80 / "the 81st is REFUSED". A new header
subsection, "Why ② is 80, and what that number does not cover", quotes
the ruling (「写入配额临时增加到80」, then 「同意」 to changing the default rather than
a per-role override) and states the residual risk: the budget is per
token PER CONTAINER, N containers on one token add up, so keep
concurrent containers per token small. The reserve-then-sleep paragraph
no longer names "the 40th".
- Rules ① min gap (3 s), ③ back-off stop marker (30 min), ④ fleet-wide
single in-flight lease and ⑤ batch gap are byte-unchanged.
`OS_PM_WRITE_HOURLY_MAX` keeps its FOR-TESTS meaning (untouched).
- Self-test: every case name tied to the cap now follows the constant
(battery `rule ②: the first write past the hourly budget is REFUSED,
with a prescription`; cases `${DEFAULT_HOURLY_MAX} writes in the window
are allowed` and `write ${DEFAULT_HOURLY_MAX + 1} is refused`; the
success line). One deliberate literal pin was added in the limits
battery, `rule ②'s default is the ruled 80 writes per token-hour`
(`DEFAULT_HOURLY_MAX === 80`), so the ruled value cannot drift without a
red; that battery's floor rises 10 → 11.
- No changeset: the diff is `scripts/pm/**` only and publishes nothing
from any released package, so this PR carries `skip-changeset`.
## Tests
<details><summary>write-pace self-test at 441a43c</summary>
```text
$ node scripts/pm/write-pace.mjs --self-test # head 441a43c, exit 0
✓ write-pace self-test: 119 cases pass across 12 batteries — the per-token key that never carries the token, the gap remainder, the refusal past the hourly budget and its prescription, the stop marker a 429 writes, the prune that keeps a long retry-after alive, the lease that kept one write in flight across real processes, the batch gap one process announced and two others obeyed, the shell door, and the nine write transports that call both halves.
```
</details>
<details><summary>Ablation: constant set back to 40 (one-shot, not
kept)</summary>
Run through `scripts/ablation-replace.mjs` against the committed head,
with a trap restore. The anchor `export const DEFAULT_HOURLY_MAX = 80;`
counted 1 before; the mutated anchor `= 40;` counted 1 on disk during
the run; the self-test exited 1:
```text
✗ rule ②'s default is the ruled 80 writes per token-hour — got 40, want 80
✗ write-pace self-test: 1 of 119 case(s) failed.
ablation-replace: ok restored: blob == HEAD (c5e4330) and `git diff HEAD` is empty
```
Exactly one case went red, the literal pin, which shows every other
cap-tied case follows the constant. After restore the anchor counts were
new=1 / old=0, and the `git hash-object` of the file equalled the HEAD
blob `c5e4330b3e7bc7e130e189e4660ba253c8418291`.
</details>
## Acceptance notes
- Repo-wide grep for the cap (`41st`, `40` near hourly/budget/per-token
phrasing, `OS_PM_WRITE_HOURLY_MAX`) across `scripts/`, `.claude/`,
`AGENTS.md`, `docs/`, `content/docs/`: no other place states the write
cap. `.claude/skills/pm-dispatch/**` and `.claude/agents/os-dev.md` do
not quote it, so neither is touched.
- One stale quote is left on purpose: `.github/workflows/lint.yml:1327`,
in the comment above the write-pace self-test step, still says "the 41st
write in an hour is REFUSED". That file is a Tier H governed surface and
outside this claim's file surface, so editing it would turn this PR
governed. It is a comment only (the step runs `--self-test`, which
follows the constant), and it is handed to the seat.
- `check-governed-merges --branch`: NOT governed, 1 path, +32 / -11.
## Verification
<details><summary>Derived gate families (dispatch-gates --commands
--repo objectstack-ai/objectstack, at 441a43c)</summary>
```text
31 derived commands, each run with $? captured before any pipe, at head 441a43c:
exit 0 node scripts/check-closing-keyword-parity.mjs
exit 0 node scripts/check-closing-keyword-parity.mjs --self-test
exit 0 node scripts/check-comment-mask-corpus.mjs
exit 0 node scripts/check-declaration-mirrors.mjs
exit 0 node scripts/check-declaration-mirrors.mjs --self-test
exit 0 node scripts/check-self-test-wired.mjs
exit 0 node scripts/check-self-test-wired.mjs --self-test
exit 0 node scripts/check-self-test-workflow-commands.mjs
exit 0 node scripts/check-self-test-workflow-commands.mjs --self-test
exit 0 node scripts/check-whole-set-label-write.mjs
exit 0 node scripts/check-whole-set-label-write.mjs --self-test
exit 0 node scripts/ci/plan-test-core-shards.mjs --self-test
exit 0 node scripts/pm/bare-root-worklist.mjs --self-test
exit 0 pnpm check:agent-test-spelling
exit 0 pnpm check:bash32-floor
exit 0 pnpm check:ci-filter-parity
exit 0 pnpm check:cli-command-ids
exit 0 pnpm check:cross-package-test-inputs
exit 0 pnpm check:driver-memory-census
exit 0 pnpm check:entry-guard
exit 0 pnpm check:gitlink-declared
exit 0 pnpm check:nul-bytes
exit 0 pnpm check:parse-guard
exit 0 pnpm check:pm-dispatch-gates
exit 0 pnpm check:pm-write-pace
exit 0 pnpm check:pnpm-filter-targets
exit 0 pnpm check:pnpm-flag-spellings
exit 0 pnpm check:ratchet-remedy-authority
exit 0 pnpm check:refd-timer-probe
exit 0 pnpm check:scripts-symbol-anchors
exit 0 pnpm check:watch-hint-literal
Run reconciliation — 31 derived, 31 run, 0 NOT-MEASURED, 0 UNRUN.
✓ dispatch-gates --ran: 31 derived famil(ies) accounted for — 31 run, 0 NOT-MEASURED (a DERIVED zero — all 31 recorded an exit code and none of them is 3).
```
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_012dn2AdARJtc4RgABPH7PHk)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 82e6da1 commit 7189fb2
1 file changed
Lines changed: 32 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | | - | |
36 | | - | |
| 35 | + | |
| 36 | + | |
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
51 | 68 | | |
52 | 69 | | |
53 | 70 | | |
| |||
157 | 174 | | |
158 | 175 | | |
159 | 176 | | |
160 | | - | |
| 177 | + | |
| 178 | + | |
161 | 179 | | |
162 | 180 | | |
163 | 181 | | |
| |||
227 | 245 | | |
228 | 246 | | |
229 | 247 | | |
230 | | - | |
| 248 | + | |
231 | 249 | | |
232 | 250 | | |
233 | 251 | | |
| |||
559 | 577 | | |
560 | 578 | | |
561 | 579 | | |
562 | | - | |
| 580 | + | |
563 | 581 | | |
564 | 582 | | |
565 | 583 | | |
| |||
1289 | 1307 | | |
1290 | 1308 | | |
1291 | 1309 | | |
1292 | | - | |
| 1310 | + | |
1293 | 1311 | | |
1294 | | - | |
| 1312 | + | |
1295 | 1313 | | |
1296 | 1314 | | |
1297 | 1315 | | |
| |||
1427 | 1445 | | |
1428 | 1446 | | |
1429 | 1447 | | |
| 1448 | + | |
| 1449 | + | |
| 1450 | + | |
1430 | 1451 | | |
1431 | 1452 | | |
1432 | 1453 | | |
| |||
1460 | 1481 | | |
1461 | 1482 | | |
1462 | 1483 | | |
1463 | | - | |
| 1484 | + | |
1464 | 1485 | | |
1465 | 1486 | | |
1466 | 1487 | | |
| |||
1469 | 1490 | | |
1470 | 1491 | | |
1471 | 1492 | | |
1472 | | - | |
| 1493 | + | |
1473 | 1494 | | |
1474 | | - | |
| 1495 | + | |
1475 | 1496 | | |
1476 | 1497 | | |
1477 | 1498 | | |
| |||
1838 | 1859 | | |
1839 | 1860 | | |
1840 | 1861 | | |
1841 | | - | |
| 1862 | + | |
1842 | 1863 | | |
1843 | 1864 | | |
1844 | 1865 | | |
| |||
0 commit comments