docs(pm-skills): the strip prescription costs the session id — name it on the write-side footer cell - #18837
Conversation
…t on the write-side footer cell The write-side footer cell already carries the mechanism on both sides: a bare REST `PATCH /pulls` appends a bare footer and keeps an existing session-URL one (+58 B), and sending a footer-less body the same way stores back exactly one — the platform's bare form. What it did not carry is what that costs: the bare form has no session id, so a body stripped per this cell's own prescription no longer records which session wrote it. One row, paid in place. Retired to pay for it: the note that the footer-deleting reading is the only observation off the criterion and its channel is denied. Its content survives in the same cell — the denied channel and its history reading one row up, and the read-back-after-every-write obligation two rows down. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Review of record on the PR thread (the queue guard's merge_group leg reads this thread and, since PR #18738, the card thread too). In-seat review of PR #18837 (#18622) by the dispatching ① Derived judgments
② Semver levelNone — no package is touched; ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #18622
Clause-②: noWritten by session
session_01Gqi43smmqjJ5sUrhfoPeKuon branchclaude/issue-18622-edit-footer-provenance— the session id is stated here, in prose, because this card is about exactly the reason that is necessary.This is a re-derivation against the tip plus one row, paid in place. The cell has grown a lot since the card was filed at 09:27Z (PR #18689, #18713, #18741, #18775, #18808 all landed on this file today), and most of what the card asked for is already carried.
The carried-map — six readings against
origin/mainad1f94e8ecThe bands re-derived on this head: the write-side footer cell is :340–:359, the issue-body cell :409–:414.
POST /pullsstores the author's session-URL footer verbatim---加页脚块时,追加一条同形页脚。」 — 「同形」 is what makes the stored block the author's, the session-URL spelling includedPATCH /pullsappends the BARE formPATCH /pulls追加一个裸页脚并保留既有 session-URL 页脚,差恰 58 字节。」 and :346 「同路送无页脚正文存回恰一条(平台裸形)⇒ 该格处方是不送页脚,⛔ 不是不重送正文。」AGENTS.md:433 「Durable attribution lives in body prose or a comment.」 and.claude/agents/os-dev.md:403 「耐久归属写进正文散文或评论,⛔ 不循环重贴页脚;完整读数住 AGENTS.md 同条。」 Nothing in :340–:359 / :409–:414 carries it, and nothing shouldPATCHsynthesises one bare block on a block-less body and re-anchors a bare-block tail to onePATCH识别按整块:送全块或不送页脚都存回恰一条,已有页脚归一末尾不复制。」 — both arms in one row; with :411 for the create-side +58 and :413 for the rule-less counter-case (total two)PATCHappends a bare block under a session-URL tailPOST /pullsstores a session-URL tail byte-exact---前后正反两向归一空行:比对正文只按首个差异偏移,⛔ 不按长度。」 — which is precisely why the file already refuses to let length be the verdict;trailing-newline-strippedis a declared clean class inscripts/pm/post-stamped.mjsWhy (c) is not written into the fact table
The card itself says 「这不是新规则」, and the ratchet's own maintainer ruling for
references/reads: 「one rule per ≤120-byte line, no rule already stated in SKILL.md」.AGENTS.md:433 already states the prescription, and.claude/agents/os-dev.md:403 explicitly routes the full reading to it — 「完整读数住 AGENTS.md 同条」. Writing 「耐久归属写正文散文」 into the fact table would be a third copy of a rule that this corpus has deliberately given exactly one home, the same content-ownership call the 2026-09-01 ruling made for the red-window rule (「红窗规则由platform-readings.md配额段独家持有」). So the new row points atAGENTS.mdinstead of restating it.Why (b′) is the residual, and why the card's own wording needed correcting
The card reads 「一次正文编辑会静默丢掉「是哪个会话写的」」 — unconditionally. On this tip that is false as stated, and :345 is what falsifies it: an un-stripped
PATCH /pullskeeps the existing session-URL block and adds a bare one, +58 bytes — attribution intact, merely duplicated. The loss happens on exactly one path: the one the cell itself prescribes at :346–:347 (send no footer, strip both spellings). Then the stored body's only attribution block is the platform's bare form, which carries no session id.A reader can get this wrong in both directions today: from :345 alone, "my session-URL footer is preserved, attribution is safe"; from the card alone, "any edit loses it". The residual sentence is the price tag on the cell's own prescription, and nothing in the cell states it.
The one row, and what paid for it
Added, at :348, immediately after the two rows whose prescription it prices (118 bytes):
Retired, the old :353 (114 bytes):
Where its content survives, all of it inside the same cell:
update_pull_request包装器删掉 PR 正文的页脚块;该通道锁 1 已拒,读作历史。」⛔ No re-wrap was used as currency; ⛔ no ceiling was raised; net line change is zero. Nothing outside the write-side footer cell was touched —
git diff --statis1 insertion(+), 1 deletion(-).Reserved bands — verified by content, md5 before and after
added_to_merge_queuerows)4b1a925b6f6004ebd8bf05ea4f477d244b1a925b6f6004ebd8bf05ea4f477d249a1ac5fab8b1c0351d95472397eb16149a1ac5fab8b1c0351d95472397eb1614/pulls/18666/files(1/1, context :209–:215, changed line :212)88505120d3f807422999b1e17e9e126688505120d3f807422999b1e17e9e1266[Self-Approval]rowed771ed2703b2ee5bcb02f29eddf4844ed771ed2703b2ee5bcb02f29eddf4844All four byte-identical. Line numbers are unmoved too: the insert lands at :348 and the retirement at the old :353, so every line from :354 on keeps its number.
The ratchet
Derived gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom the worktree, no hand-fed path list. Change set: 1 path,.claude/skills/pm-dispatch/references/platform-readings.md, three-dot against merge basead1f94e8e. Every exit code captured redirect-then-$?.check:doc-formula-expressionsanswered exit 3 PREREQUISITE NOT MET on its first run — 「the workspace package@objectstack/formulais not built」, with@objectstack/lintunbuilt as a second unmet prerequisite. Built under the shared verify lock (bash scripts/pm/os-verify-lock.sh -c "NODE_OPTIONS=--max-old-space-size=4096 pnpm --workspace-concurrency=2 --filter '@objectstack/lint...' --filter '@objectstack/formula...' build",VERDICT command-exit 0 · held the lock 152s · waited 0s) and re-run: the 0 above is that second run.Reconciliation,
--ranwith a code recorded per family:One family was run beyond the derived union, because the derivation marked its roster ⛔ 「roster under .claude, which one of your paths is in」 and said the silence is not evidence in either direction:
Repo-wide, at the final commit
deaa1d0fd7:Byte discipline:
grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'over the edited file returns no hits (exit 1), beyondcheck:nul-bytesabove.Out of scope, noted here and reported to the seat
To file (class a, a fact-table row a merged PR falsified). :357 reads 「送全块即触发该归一 ⇒
post-stamped的body档把这点空白判mutated,净零字节良性告警。」 PR #18786 (#18693) landed at94b3f37be3, on this head: the body-mode trailing-rule re-anchor is now its own declared clean classfooter-re-anchored, exit 0, printingread-back: clean, andbody_mutatedis false. So that row is wrong on both the class word and 「告警」. It is a different reading in a different part of the cell, it needs a fresh measurement rather than a mechanical rewrite, and this card's dispatch bounds the diff to the residual — so it is reported, not fixed here. Dedupe words:post-stamped body mutated·footer-re-anchored·platform-readings 357·classifyReadBack class· 「净零字节良性告警」.Noted, not filed. #18686's create-side tension (:343's 「PR 正文页脚不带前置横线」 against :348's fourth form) was read and deliberately left alone — it is the next card on this cell and its controlled comparison was not run here. Successor: card #18686, already open and queued behind this one.
Verification method note
This PR body was created with a tail of blank line + rule + the session-URL footer block, which is :350's measured no-append shape on the create side and
AGENTS.md's prescribed form —AGENTS.mdwins over :343 where the two differ, per its own precedence line. The body was read back after the write.Generated by Claude Code