Skip to content

Commit 287eb4c

Browse files
docs(agents): say how a return-delivered durability seam is declared (#19214)
Fixes #16233 ## What changed One paragraph of `AGENTS.md` — the "Degradation log levels" block that used to end at lines 938-943 on `24d622b94`. The old text told the author of a durability seam to "declare **how it delivers** instead — `FAILURE_PROPAGATION_CALLEES` (repo-wide names) or the function-scoped `FAILURE_PROPAGATION_SITES`". Both maps key on the **name of a callee the `catch` reaches** (`scripts/check-durability-degradation-log-level.mjs:505`, `:513`), so a `catch` that delivers its failure by **returning** an outcome object has nothing to put in either one — and the only two remaining ways to green that gate are the two the gate's own header rejects: a baseline entry for correct code, or a bolted-on `logger.error`. The rewritten paragraph splits the declaration rule by **how the failure leaves the `catch`**: - delivered by CALLING something → name that callee, as before (both maps, unchanged); - delivered by RETURNING an outcome object → **no callee to declare**; never added to `DURABILITY_CRITICAL_CALLEES` or either `FAILURE_PROPAGATION_*` map, never baselined, never given a `logger.error` to satisfy the checker; pinned instead by **its own file's test** asserting the returned failure outcome (the `failed`-receipt case is the reference shape), with its population read from `scripts/measure-return-propagating-durability-seams.mjs`. The invariant is untouched: silent data loss must be loud. The gate is untouched — its fourth honest limitation (`scripts/check-durability-degradation-log-level.mjs:79-99`) already records this boundary and already names the census script, so no line of that script needed to move. ## Evidence Census re-measured on this branch, reproducing the ruling's numbers exactly: ``` node scripts/measure-return-propagating-durability-seams.mjs --sites :: exit 0 2620 non-test source files · 2968 try/catch · 250 guarding a declared durable call · 21 returning a constructed failure object on every path MEMBERS 12 [1] gate sees today 0 · [2] write-shaped 4 · [3] durable on the merits 8 ADJACENT 5 · EXCLUDED 4 ``` The instrument this paragraph governs: ``` pnpm check:durability-log-level :: exit 0 ✓ durability-degradation log levels: 36 durability-critical catch seam(s), all loud, rethrowing or propagating to the caller (4 propagating, declared) ✓ read-seam invention: 68 read seam(s), none invents an unreported answer ``` `node scripts/pm/dispatch-gates.mjs --commands` derives 14 families for this change set; all 14 were run and reconciled with `--ran` (14 derived, 14 run, 0 UNRUN). 13 green: ``` 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 pnpm check:agent-test-spelling :: exit 0 pnpm check:docs-audit-scope :: exit 0 pnpm check:driver-memory-census :: exit 0 pnpm check:nul-bytes :: exit 0 pnpm check:pm-governed-merges :: exit 0 pnpm check:pm-governed-prose :: exit 0 pnpm check:pm-skill-id-lint :: exit 0 pnpm check:refd-timer-probe :: exit 0 pnpm check:required-contexts :: exit 0 pnpm check:watch-hint-literal :: exit 0 ``` ## ✅ The line ceiling — ruled, raised, and green The maintainer ruled the budget. His words, verbatim and untranslated: > 1. #19214 / 卡 #16233 —— AGENTS.md 行预算, A 批 +10(1099→1109) Given as a live instruction to `session_019srGWGCBBCBHqcDoRZpQRh` and recorded on card #16233 as comment `5750261694`; it rules the line budget that the standing letter-C ruling `5716260390` left unruled when it named the text. ⇒ `scripts/pm/check-skill-line-ratchet.mjs` now carries `['AGENTS.md', 1109]`, with the raise recorded above the entry in that file's own ruled-raise convention — measured cost, the re-measured rewrap headroom with its widths named, the ruling verbatim, and the standing `CROSS_FILE_MOVES` sentence. ``` pnpm check:pm-skill-ratchet :: exit 1 → exit 0 ✓ check-skill-line-ratchet: AGENTS.md is 1109 lines (ceiling 1109; headroom 0). ✓ check-skill-line-ratchet self-test: 157 cases pass — including “every live ruled-raise record quotes its ruling, dates it, and names a positive line count”, which is the gate validating this very comment block. ``` ⚠️ **Two corrections to the numbers this body carried before**, both measured rather than inherited: - The rewritten paragraph measures **21 / 21 / 20** lines at 86 / 88 / 90 bytes — not 21 / 20 / 20 — and as landed it has four lines above 88 bytes (89, 90, 89, 89; max 90), so it sits at **≤90 B**, not at 88 B. The conclusion is unchanged and if anything stronger: at 88 B a rewrap would **cost** a line. - “0 lossless rewrap headroom at three widths” holds only for widths **≤90 B**. Re-measured with the gate's own `wrapLine`, the paragraph reflows to 18 lines at 100 B and 15 at 120 B (the whole section 88 → 69 at 120 B). ⇒ the honest justification for the raise is **not** that no width saves lines, it is that re-wrap is **not legal currency here**: this file's 2026-08-17 rule refuses re-wrap funding, and the 120-byte cap documents itself as codifying the corpus's existing ≤91-byte ASCII wrap rather than mandating a reflow to it. **Clause-②: no** — no published accept set, public export, enum member, error code or authorable key moves; the surface is governance prose plus one shrink-only ratchet data value. ### Landing is still the maintainer's hand `node scripts/pm/check-governed-merges.mjs --pr 19214` → **exit 3**, *GOVERNED — a human merge is the review record for this PR (#9495 regime)*, `AGENTS.md` ×1, landing tier H; the second path, `scripts/pm/check-skill-line-ratchet.mjs`, is **not** on the register and adds no governed path. ⇒ This PR stays **draft**: ⛔ no ready flip, ⛔ no enqueue, ⛔ no auto-merge by any seat. A line budget is a budget, not a landing permission. Verified independently by the accepting seat on head `aa2e7408d` (⛔ not taken from the dev's report): two files vs `origin/main` — `AGENTS.md` +20/−10, byte-identical to the previous round, so the ruled paragraph was **not** shrunk to buy lines — and `check-skill-line-ratchet.mjs` +29/−1, one data value plus the comment block. `origin/main` was merged in twice (`32d6e4775`, `aa2e7408d`); the previous head `f2c3ebf6d` is still an ancestor, so no history was rewritten on this branch. 35 derived gate families, 35 run, 0 NOT-MEASURED, every one exit 0; `check:ratchet-remedy-authority` re-read and **unmoved** (this script classifies `excluded`). ## 维护者速读(草稿) **改了什么** `AGENTS.md` 里讲「降级日志等级」的那一段,重写了最后半段。原文要求:把失败交给调用方的 `catch`,必须在门禁的两张表里声明「它是怎么交付的」。但那两张表的键都是**被调函数的名字**,而 一个用 `return { ok: false, error }` 把失败交还给调用方的 `catch` **根本没有可填的名字**。新文 字按「失败是怎么离开 catch 的」分成两种:靠**调用**交付的照旧声明被调者;靠**返回**交付的明确 写清「没有名字可声明」,不进任何名单、不进 baseline、也不准为了让门禁变绿而硬加一行 `logger.error`,改由**该文件自己的测试**钉住,并给出普查脚本作为「这类缝一共有多少」的唯一读数 来源。⭐ 不变量本身没有动:静默的数据丢失必须吵。 **为什么改** 这是一条**写在制度里却没人能照做**的规则。今天不出事,只因为门禁当前看得见的那一类里这种缝是 0 个;树上真实存在的是 **12** 个(普查脚本现读,与裁决数字逐字一致),每一个都已由自己文件的 测试钉住,没有一个是未受保护的降级。真正的缺陷是那句话会把下一个开发者送进死路:正确的代码会 把门禁弄红,而唯二能弄绿的办法都是门禁自己明文拒绝的。本次改的是**文字**,仪器一行未动。 **风险与代价(含回滚)** - 代价:`AGENTS.md` 这份受管文件的行数上限**已经顶满**(1099,余量 0),这一段净增 **10 行**。 折行压缩买不来这 10 行(实测:旧段在 86/88/90 三种宽度下都是 10 行),所以要么由维护者裁一个 行数预算把上限抬到 1109,要么这段文字落不了地。开发席不自行抬上限。 - 风险:低。只改治理文本,不改任何运行时代码、不改门禁判据、不改任何名单或 baseline; `pnpm check:durability-log-level` 在本分支现读仍是绿,36 条缝的判决一条没变。 - 回滚:单文件单段落,`git revert` 即可,零运行时影响。 **席位意见** 同意落地。`domain:spec` 座位 5(`session_019srGWGCBBCBHqcDoRZpQRh`,座位贴 #19357)在维护者直派 通道下复核并验收:上面每一条读数本席都在 head `aa2e7408d` 上独立重取过,⛔ 未采信 dev 的终报自 述;棘轮只动了 `:1466` 那一个数,`AGENTS.md` 正文一字未改。⚠️ 本 PR 的卡归 `domain:devx` 席 (#6023),本席只做验收与记录,⛔ 不接管该卡、⛔ 不改它的标签或 assignee。 **你要做的** 1. 读上面那段新文字,确认它就是裁决要的意思(尤其「返回式交付的缝由它自己文件的测试钉住」这一 条)。 2. ~~裁一个**行数预算**~~ —— **已裁:A,+10(1099→1109)**。上限已按该裁定抬到 1109, `pnpm check:pm-skill-ratchet` 由 exit 1 转 **exit 0**,裁决原话已写进棘轮注释块。此项无需再做。 3. 人工把这个 draft PR 合并 —— 受管面,**人工合并即复核记录**(#9495),⛔ 任何席位都不翻 ready、不入队、不挂 auto-merge。这是本 PR 余下的**唯一**一步。 <sub>Authored by Claude Code, session `session_017ef78bLdybu3AffehKkhfk` (`domain:devx` seat, PR #19214's own branch). Body last revised by `domain:spec` seat 5, `session_019srGWGCBBCBHqcDoRZpQRh`, under the maintainer's direct-dispatch channel — the ruling record above. ⛔ No seat flips this PR to ready.</sub> --- _Generated by [Claude Code](https://claude.ai/code)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent adbdbc5 commit 287eb4c

2 files changed

Lines changed: 49 additions & 11 deletions

File tree

‎AGENTS.md‎

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -931,16 +931,26 @@ restores durability, or the explicit opt-out that makes the degradation delibera
931931
(`suspendedRunStore: 'memory'`, `OS_SKIP_SCHEMA_SYNC`). Say it **once**, at the first
932932
degradation, not once per failed write.
933933

934-
**Do not over-apply it.** Escalating a functional degradation to `error` trains
935-
everyone to skim `error`. An `if (!service)` composition branch is usually functional
936-
and belongs at `warn`; a `catch` around a write, a DDL call, or a store initialization
937-
is where this rule bites. **And a failure handed to the CALLER is not a degradation at
938-
all** — the third legal answer: a `catch` that answers `errorFromThrown(e, 400)`, or a
939-
batch whose contract IS a per-item outcome report, does not look normal from the
940-
outside — the requester was told. Do **not** bolt a `logger.error` onto such a site;
941-
declare **how it delivers** instead — `FAILURE_PROPAGATION_CALLEES` (repo-wide names)
942-
or the function-scoped `FAILURE_PROPAGATION_SITES` in the checker, which then proves
943-
structurally that *every* path out of the `catch` delivers.
934+
**Do not over-apply it.** Escalating a functional degradation to `error` trains everyone
935+
to skim `error`. An `if (!service)` composition branch is usually functional and belongs
936+
at `warn`; a `catch` around a write, a DDL call, or a store initialization is where this
937+
rule bites. **And a failure handed to the CALLER is not a degradation at all** — the
938+
third legal answer: a `catch` that answers `errorFromThrown(e, 400)`, or a batch whose
939+
contract IS a per-item outcome report, does not look normal from the outside — the
940+
requester was told. Do **not** bolt a `logger.error` onto such a site; declare **how it
941+
delivers** instead — and which declaration exists depends on how the failure leaves the
942+
`catch`. Delivered by CALLING something: name that callee, repo-wide in
943+
`FAILURE_PROPAGATION_CALLEES` or function-scoped in `FAILURE_PROPAGATION_SITES`, and the
944+
checker then proves structurally that *every* path out of the `catch` reaches it.
945+
Delivered by **RETURNING** an outcome object — `return { ok: false, error }`, a `failed`
946+
receipt — there is **no callee to declare**: the delivery IS the constructed value, and
947+
both maps key on a name. ⛔ Never add such a seam to `DURABILITY_CRITICAL_CALLEES` or to
948+
either `FAILURE_PROPAGATION_*` map, ⛔ never baseline it, ⛔ never bolt on a
949+
`logger.error` to green the checker: the shape is outside its reach by construction. Pin
950+
it in **its own file's test** asserting the returned failure outcome (the
951+
`failed`-receipt case is the reference shape), and read its population from
952+
`scripts/measure-return-propagating-durability-seams.mjs`. ⭐ The invariant does not
953+
move: silent data loss must be loud, so what this checker cannot see, that test holds.
944954

945955
**It has teeth**: `pnpm check:durability-log-level`
946956
(`scripts/check-durability-degradation-log-level.mjs`; its header is the authority)

‎scripts/pm/check-skill-line-ratchet.mjs‎

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1435,7 +1435,35 @@ export const CEILINGS = new Map([
14351435
// 并按实测行数抬上限」; recorded by the director on #15410 comment 5682595374, which
14361436
// also refuses option D). AGENTS.md is not a CROSS_FILE_MOVES destination, so no
14371437
// `ruledRaises` record applies. Landed count, headroom 0, same convention.
1438-
['AGENTS.md', 1099],
1438+
//
1439+
// 1099 → 1109 (card #16233): § Degradation log levels' third-legal-answer
1440+
// paragraph brought to the instrument, per letter C — a `catch` that delivers by
1441+
// RETURNING an outcome object (`return { ok: false, error }`, a `failed` receipt)
1442+
// has no callee to declare, so it is ⛔ never added to
1443+
// `DURABILITY_CRITICAL_CALLEES` or to either `FAILURE_PROPAGATION_*` map,
1444+
// ⛔ never baselined and ⛔ never log-bolted to green the checker; it is pinned by
1445+
// its own file's test and its population read from
1446+
// `scripts/measure-return-propagating-durability-seams.mjs`. Until this line the
1447+
// text prescribed, for all 12 censused seams, the two remedies the gate's own
1448+
// header refuses — correct code reds the gate, and the only two ways to green it
1449+
// were the two it forbids. +10 lines, measured: the paragraph goes 10 → 20
1450+
// physical lines and the file 1099 → 1109, and it is bought by CONTENT, not by
1451+
// bad wrapping. Re-measured on the merged tree with this gate's own `wrapLine`,
1452+
// at the width the section is actually typeset at (median 85 B, p90 89 B, max
1453+
// 90 B — inside the ≤91-byte ASCII-prose convention the 120-byte cap above
1454+
// codifies): a greedy rewrap returns exactly the 20 lines the paragraph already
1455+
// occupies at 90 B, and 21 at 88 B ⇒ 0 lossless-rewrap headroom. Lines come back
1456+
// only by re-typesetting ASCII prose ABOVE that convention (18 at 100 B, 15 at
1457+
// 120 B; the whole section 88 → 69 at 120 B), which is the reflow that cap
1458+
// documents itself as NOT imposing — and re-wrap funding is refused per the
1459+
// 2026-08-17 rule in any case. Maintainer ruling, verbatim and untranslated:
1460+
// 「1. #19214 / 卡 #16233 —— AGENTS.md 行预算, A 批 +10(1099→1109)」
1461+
// — the maintainer's live instruction to `session_019srGWGCBBCBHqcDoRZpQRh`,
1462+
// recorded on #16233 comment 5750261694; it rules the line budget that the
1463+
// standing letter-C ruling 5716260390 left unruled when it named the text.
1464+
// AGENTS.md is not a CROSS_FILE_MOVES destination, so no `ruledRaises` record
1465+
// applies. Landed count, headroom 0, same convention.
1466+
['AGENTS.md', 1109],
14391467
// #9965: root CLAUDE.md is the other repo-root instruction file — same read
14401468
// path (every seat session), same governance (Prime Directive #14). It is
14411469
// structurally growth-prone in the way the ratchet is built for: it exists to

0 commit comments

Comments
 (0)