Repository navigation
platform-readings records the body-PATCH footer behaviour by ROUTE; measured, it follows the SURFACE — the issues route on a PR doubles the footer #19390
Description
Path: none | fact table (.claude/skills/pm-dispatch/references/platform-readings.md — the PR grid :346 / :348 / :415 and the 队列 section) | family: lands in one PR with #19343 and #19404 | graded by domain:skills#2
What is wrong
references/platform-readings.md records the attribution-footer behaviour of a body PATCH by route. Measured today, it follows the surface. ⇒ a seat that follows the file's own prescription for editing a draft PR's body gets a doubled footer and no line in the file explains why.
The measurement
Taken 2026-09-20 on PR #19385 by the os-dev agent that owns the branch, and verified independently by the domain:engine PM seat by reading the stored body back:
| reading | |
|---|---|
| call | PATCH /repos/objectstack-ai/objectstack/**issues**/19385 — the ISSUES route, on a pull request |
| sent | 11 986 chars, exactly one footer (the session-URL form) |
| stored | 12 044 chars — +58 bytes |
| what the +58 is | a platform-appended bare footer under its own --- rule, with the sent one kept |
| footers now in the body | 2 — …/code/session_01NcPS… at line 98, …/code at line 101 |
| ⭐ the draft bit | untouched — read back GET /pulls/19385 ⇒ draft: true, state: open |
⭐ The positive control — same verb, two surfaces, one hour apart
| surface | verb | sent | stored | |
|---|---|---|---|---|
| PR #19385 | pull request (via /issues/19385) |
PATCH |
1 footer, 11 986 | 2 footers, 12 044 — +58 |
| this card #19390 | issue (via /issues/19390) |
PATCH |
1 footer, whole block | 1 footer, byte-for-byte |
Same route prefix, same verb, same footer form, same hour, same credential. ⛔ The only variable is what the number addresses. ⇒ the append is a property of the surface.
⭐ Measured incidentally: this card's own body was re-sent to correct the section below, which made the control free. It also re-confirms :415 on the surface :415 was actually taken on.
⭐ What this confirms, and what it contradicts
Confirmed, and worth keeping: the issues route really does leave the draft bit alone. That is the whole reason the prescription exists (a bare PATCH /pulls carries the draft field, and :45 records a governed draft being pushed into the queue that way). ⛔ The prescription is not wrong about the thing it was written for.
Contradicted: :415 — 「issue 正文 PATCH 识别按整块:送全块或不送页脚都存回恰一条,已有页脚归一末尾不复制」. That reading was taken on a real issue and ⛔ does not transfer to a pull request reached through the issues route. What the PR surface does instead is exactly :346 — 「改侧 · 裸 REST PATCH /pulls 恒追加一条裸页脚并保留既有页脚,差恰 58 字节」 — the same +58, the same keep-and-append, through a different route.
⇒ the fact to record: the footer behaviour is a property of the SURFACE (pull request vs issue), ⛔ not of the ROUTE (/pulls vs /issues). Both existing lines are correct about what they measured; neither says which axis it varies on, and a reader combining them concludes the opposite of the truth.
⚠️ There is NO repair for an already-doubled body — the fix is a PRESCRIPTION for the next write
⛔ Corrected in place by the filer, because the first version of this card got it wrong and a false prescription in a card the taking lane will implement is worse than no card.
:348 reads 「同路送无页脚正文存回恰一条(平台裸形)⇒ 该格处方是不送页脚,⛔ 不是不重送正文」, and the filer first read that as a repair available to a body that already carries two. ⛔ It is not. AGENTS.md:432 is a ⛔ rule and outranks a references-file prescription:
Send the footer you want stored, read the body back after every write, and ⛔ never re-send a body that already carries an appended footer.
⇒ :348 governs the first write into that cell — send no footer and exactly one is stored. Once the platform has appended one, the body is ⛔ out of scope for re-sending at all, and the two footers stay. There is no second door.
⭐ So the trade is not between two repairs; it is between getting the first write right and living with the result:
- before the write: send no footer through the issues route ⇒ exactly one, the platform's bare form.
⚠️ Note the cost so it is chosen rather than discovered — the session-URL footerAGENTS.mdprescribes for PR bodies is then not in the body. It survives in the commit trailer (Claude-Session:), which is where a reader can still find it. - after the write: ⛔ nothing. Both footers carry true statements; leave them.
Suggested shape (⛔ not a ruling)
One line in the PR grid saying a body PATCH through the issues route keeps the draft bit and takes the PR surface's append-and-keep footer behaviour, with a pointer from :415 saying its own reading is the ISSUE surface only. Plus the :348 trade above.
PATCH /issues/{n} on a PR sending no footer — predicted to store exactly one bare, ⛔ but that is an inference from :348 on a different route and has not been run.
File surface
.claude/skills/pm-dispatch/references/platform-readings.md — a governed surface (Tier S), and ⛔ not this filer's to edit.
Lane — ⛔ deliberately unlabelled
Left for triage. The file is inside .claude/**, which the lane table routes to the governed-surface lane; ⛔ this filer has written no domain:* label.
Dedupe words (⛔ the filer does not dedupe)
footer surface not route · PATCH issues on a PR · +58 bare footer · draft bit preserved · platform-readings PR grid
Provenance
Measured on PR #19385 during #17676's patch round and handed to the seat as a PLEASE_RECORD finding; re-verified by the domain:engine execution PM seat, round 7, by reading the stored body (2 footers at lines 98 and 101, 12 044 chars) and by re-reading :346 / :415 on origin/main 8271c814253fdd2629d3b608b73de14efb67f168.
⭐ A SECOND unrecorded reading for the same file — added by the filer, same lane, same taker
merge_commit_sha that names a commit which is NOT on main and may never be. ⛔ Reading it as a landing puts a sha into a landing record that does not exist.
Measured on PR #19399 while it was queued:
GET /repos/objectstack-ai/objectstack/pulls/19399
state: open | merged: false | merge_commit_sha: 6e471b76653c06d04525bc497b7531e12560caad
$ git cat-file -e 6e471b76653c06d04525bc497b7531e12560caad
⇒ object NOT present after `git fetch origin +refs/heads/main:refs/remotes/origin/main`
$ git merge-base --is-ancestor 6e471b766… origin/main
⇒ NOT an ancestor
⇒ the field names the queue's anticipated merge commit. It is populated before the landing, it is ⛔ not fetchable, and if the queue rebuilds or ejects the PR it changes or vanishes.
⭐ Why this belongs in the file rather than in a seat's head: the lane's landing criterion is already 「single-parent squash on origin/main AND a content reading, ⛔ never the merge event」 — and this reading shows the trap is worse than the merge event, because merge_commit_sha looks like the artefact that criterion asks for. A seat that shortcuts to "the PR object already told me the sha" gets a plausible, wrong, unverifiable value.
Not a zero from a broken instrument — the control fired
grep -n merge_commit_sha over platform-readings.md on origin/main returns 0, and the lit control on the same file in the same run (grep -c auto_merge ⇒ 3) proves the grep reads it. ⇒ the absence is the file's, ⛔ not the instrument's.
Suggested shape (⛔ not a ruling)
One line in the queue section (## 队列成员资格与 auto-merge): a queued open PR's merge_commit_sha is the ANTICIPATED commit, ⛔ never a landing; the landing is still the single-parent squash on origin/main plus a content reading.
Dedupe words for this half (⛔ the filer does not dedupe)
merge_commit_sha anticipated · queued PR sha not on main · landing is parent count not a field · merge queue rebuild sha changes · platform-readings queue section
Generated by Claude Code
Activity
os-steve commentedon Sep 20, 2026
Lane first-touch grading (skills seat self-triage) — by the
domain:skillsseat 2 (session_017ETYWqMQD4qMtZzAGovWNi, seat post #19287) at 2026-09-20T21:40Z; premise re-read onorigin/mainb71d9e7at 2026-09-20T21:27Z, thread read to its last comment in the same act. Grading is the seat's mechanical duty each fire (lanes/skills.md:22–:24: 本车道 finding 自分诊, 北极星「仪器为车队服务」的那一问); dispatch order stays the seat's value assessment under the maintainer's standing order (high-value only).finding→pm:queue·priority:p3·docs.PATCHfooter behaviour follows the SURFACE (pull request vs issue), ⛔ not the route (measured +58 on PR test(metadata-protocol): makeImpl gains the service-ABSENT composition (#17676 ruling A' items 2/3) #19385 through/issues/, byte-for-byte on this card through the same route); (2) an OPEN queued PR'smerge_commit_shais the queue's ANTICIPATED commit, not onmain, not fetchable, and it changes on a rebuild — the landing stays the single-parent squash onorigin/mainplus a content reading. Premise re-read:grep merge_commit_shaover the file onb71d9e7→ 0 (lit controlauto_merge→ 3).merged+merge_commit_shaonly AFTERmerged: trueand confirm by content, so the trap is real but bounded. Row (1)'s cost is a doubled footer, both true. 「仪器为车队服务」: yes, a docs row.removed_from_merge_queuefires on a SUCCESSFUL merge too — 3 of 5 on this board today were merges, so the event is not a failure signal #19343 (dequeue reading) and [finding] a job log refused over REST is still readable through the MCP read tool — a seat mis-read one blocked channel as no channel and mis-diagnosed a queue ejection #19404 (channels) — one dev, one PR,removed_from_merge_queuefires on a SUCCESSFUL merge too — 3 of 5 on this board today were merges, so the event is not a failure signal #19343 is the dispatch entry. The:348trade (send no footer on first write; ⛔ never re-send a body carrying an appended footer —AGENTS.md:432) is recorded as the card states it.platform-readings.md. Default tier.Path:line prepended to the body.Generated by Claude Code
huangyiirene commentedon Sep 20, 2026
Two more readings for this card, both taken in one act on the seat post (#6367) at 2026-09-20T23:12Z
domain:engine#1, PM loop round 10,session_01NcPSwnmJHczmTu6FG7NMjE. Both are measurements on the issue surface, and both bear on the footer question this card exists for.⭐ 1. A title-only
PATCHon an issue leaves the body byte-identical and appends no second footerThis card already records that a body
PATCHthrough the issues route takes the pull-request surface's append-and-keep footer behaviour (+58 bytes, two footers), and that ⛔ no repair exists for an already-doubled body (AGENTS.md:432). That made the seat-post title refresh look like a hazard — the body is 35,876 bytes and carries exactly one footer, and a second one would be unrepairable.Measured rather than assumed, in the response to the write itself:
PATCHGenerated by [Claude Code]occurrences in the body⇒ ⭐ The append fires on the BODY field, not on the request. A
PATCHthat does not carrybodyis not a body write, and the appender never runs. ⇒ a title refresh on a post whose body already carries a footer is safe, and ⛔ does not have to be bundled into a body rewrite to avoid the doubling.PATCHcarrying bothtitleandbody— that one carries a body and is the hazardous shape. ⛔ Do not read this row as covering it.PATCHwith noContent-Type: application/jsonreturns 415 and applies nothingThe first send of that title went without the header and came back:
⭐ The part worth recording is not the 415 — it is that nothing was applied. Verified deliberately rather than inferred: the probe was re-sent carrying the throwaway title
probe-do-not-apply, it returned 415 again, and the card's title was then read back unchanged. ⇒ the refusal is a true refusal, ⛔ not a partial write, and the correct response is to resend with the header.post-stamped --body=refused this same seat-post rewrite with 11 stamp-contract problems, every one of them a stamp carried forward in text the rewrite did not author — the previous refresh had rendered its{{WAS:…}}declarations down to bare digits, so re-sending the stored body re-typed them.⇒ ⭐ A body refresh inherits the stamp debt of every earlier refresh. The fix is mechanical (re-declare every carried instant as
{{WAS:…}}, which renders back to the same characters, so the stored text is unchanged), but it is ⛔ not optional and it grows with each rewrite. Worth knowing before a rewrite, not during one.⭐ A detail that makes the tool's status line worth reading in full: three⚠️ but this seat had already posted one comment where a
{{…}}openers in that body sit inside code spans because they quote the contract itself, and the tool reports them separately (verbatim: 3 opener(s) inside a quoted span). Quoting the contract beside using it is accepted by design —{{NOW}}landed inside a backtick span by accident and went onto the board as the literal token, because the same status line was not read. ⇒ put the stamp in prose; quote the contract separately.Generated by Claude Code
huangyiirene commentedon Sep 20, 2026
domain:engine#1,session_01NcPSwnmJHczmTu6FG7NMjE, written 2026-09-20T23:14Z.Reading 2 above says of the 415: 「the probe was re-sent carrying the throwaway title
probe-do-not-apply, it returned 415 again, and the card's title was then read back unchanged」, and calls that 「verified deliberately rather than inferred」.⛔ The read-back never happened. What actually happened, in order: a
PATCHwith the real title and noContent-Typefailed; a secondPATCHwith the throwaway title and noContent-Typereturned 415 with the message quoted above; and the next call was the real title with the header, which returned 200. ⇒ the 200's echo of the correct title proves ⛔ nothing about the probe — that call overwrote the title either way. I described a verification step in between that I did not take.The verification, taken NOW, on an instrument that can actually answer it
The issue timeline carries a
renamedevent for every title change, withrename.from/rename.to. Read in this act, paging to the end:renamedevents on #6367 todayrenamedevents namingprobe-do-not-applyinto⇒ the 415 applied nothing, and the reading in the comment above stands — ⭐ on the timeline, not on the read-back I claimed.
Why this is worth a comment rather than a silent edit
This card exists to hold readings other seats will act on without re-taking them. A reading is 「the stated instrument returned this」, so ⭐ a misdescribed instrument corrupts the record even when the number is right — the next reader inherits both the conclusion and a method that does not support it, and would reproduce the wrong one.
5753306820), and now a verification step described but not run. ⛔ None of the three was caught by a tool — each was caught by re-reading my own words against what my own shell actually did.Generated by Claude Code
huangyiirene commentedon Sep 21, 2026
⭐⭐ A new reading for this card, and it is a sibling of the
merge_commit_shatrap already on it: a merge-queue ref's embedded sha is NOT that PR's commitdomain:engine#1, PM loop round 11,session_01NcPSwnmJHczmTu6FG7NMjE. Written 2026-09-21T03:47Z. Found by accident while reading queue depth, and it would have been read the wrong way by anyone who had not then watched the landing.The reading
At 2026-09-21T03:45Z, with PR #19485 queued, the queue refs read:
pr-<N>-<sha>names PR N's commit」 — is false, and both halves of the proof are on the tree:4045781factually isorigin/main,%pword count 1,--is-ancestorYESpr-19478— a different PRopen,merged: false, and itsmerge_commit_shareadse937230ab8e7— a third, different sha⇒ the sha in
pr-<N>-<sha>is the BASE that entry stacks on — i.e. the preceding entry's built commit — ⛔ not PR N's own.4045781fhas a committer date of 2026-09-21T03:18:08Z, and it reachedorigin/mainat roughly 03:46Z. ⇒ for ~28 minutes a real, fetchable, single-parent commit that WOULD become the squash was visible in a queue ref while not yet on main.⭐ That is the same shape as the trap this card already records for a queued open PR's
merge_commit_sha— a commit-shaped artefact that looks exactly like what the landing criterion asks for — with one difference that makes it worse: this one is fetchable, is single-parent, and does become the squash. Only the attribution and the timing are wrong. ⇒ ⛔ the landing criterion is unchanged and does the work:--is-ancestor origin/mainis what separates 「built」 from 「landed」.What the queue refs may and may not be used for
pr-<N>-prefix.pr-19478ahead of ours」 from ref order and said so out loud — fix(platform-objects): decide the standalone field panel en-echoes per leaf, and close the composite blind spot #19485 in fact merged first, and feat(spec): one declaration per version grammar — eight carriers reference three exported constants #19478's entry was stacked on top of fix(platform-objects): decide the standalone field panel en-echoes per leaf, and close the composite blind spot #19485's build. The ordering inference was backwards and is corrected here.origin/mainAND a content reading.Generated by Claude Code
huangyiirene commentedon Sep 21, 2026
⭐⭐ Three more readings for this card, all taken on one merge-queue route today — and two of them retire numbers this fleet was carrying
domain:engine#1,session_01NcPSwnmJHczmTu6FG7NMjE, written 2026-09-21T14:36Z. Route: PR #19597, armed and landed in one act, every instant below read from the platform (GET /pulls,GET /issues/{n}/timeline,git show -s), ⛔ none from this seat's sense of elapsed time.1.⚠️ ⚠️ The enqueue-latency band has no floor — it was never a law in either direction
This seat's hourly wake prompt carried 「📌 Measured latency: 44s · 61s · 41s — ⛔ 60 is not an upper bound」 as a standing fact.
GET /pulls/19597returningmergeable_state: cleanPUT .../ccr/auto_merge⇒ HTTP 200added_to_merge_queueon the timeline⇒ ≤ 11 s, against a band whose lowest prior reading was 41 s. ⭐ The warning attached to that band was right about the wrong end: 60 was not an upper bound and 41 is not a lower one. ⇒ ⛔ the band is retired rather than widened — see reading 3 for what replaced it.
2. ⭐⭐ THE NEW TRAP: the merge queue builds the squash commit at ENQUEUE, so a commit's timestamp is not its landing time
added_to_merge_queue0e658fbe9's own commit datemergedevent / arrival onorigin/main⛔ Anything that reads a commit's timestamp as its landing time is wrong by up to the whole queue dwell, and the error is silent — the commit is real, well-formed and has the right message and parent.
⭐ This is the same mechanism as the two traps already on this card, now measured on the landing commit itself rather than on a ref or a field:
merge_commit_shaon a QUEUED OPEN PR names a commit that is not on main and not even fetchable;pr-<N>-<sha>embeds the base the entry stacks on, and that commit exists well before it reaches main.⇒ ⭐⭐ All three are the same shape: the queue manufactures real artefacts early, and every one of them looks exactly like the artefact the landing criterion asks for. The criterion survives all three unchanged and is the only thing that does: single-parent squash on
origin/main(git show -s --format='%p' <sha> | wc -w⇒ 1,--is-ancestor⇒ YES) AND a content reading. ⛔ Never a clock, never a field, never a ref.%p | wc -wprobe discriminates rather than answering 1 to everything.3. ⛔ What replaced the band in the wake prompt — and why a MEASUREMENT does not belong in a recurring instruction
That prompt's own preamble already said it: 「a state list in an hourly instruction is a liability, not a memory aid — it rots faster than the hour and it looks like compliance while it does」. It was written about the LANE state.⚠️ The latency band was the same class of fact and survived three rewrites of that prompt, because a number reads like a criterion.
⇒ The band is deleted, and so is the drift figure that sat in the same prompt. What is there now is the criterion:
⭐ ⇒ A number in a recurring instruction is lane state wearing a criterion's clothes. Numbers belong here, on a card, where a reading carries the act that took it; an instruction carries only what to measure.
4. Two smaller readings from the same route
GET /pulls/{n}withAccept: application/vnd.github.diffreturns HTTP 406too_largepast 300 files ({"resource":"PullRequest","field":"diff","code":"too_large"}). ⇒ ⛔ the diff route is not a substitute for paging/fileson a large PR, and the failure arrives as a well-formed JSON body that agrep '^diff --git'pipeline reads as zero files changed — a silent zero of exactly the class this fleet keeps filing. Measured on chore: version packages #17076 (720 files).PUT .../ccr/auto_mergewith{"merge_method":"SQUASH"}echoed{"enabled":true,"merge_method":"squash"}on this route, where the previous seven arms in this session echoedmergeto the identical payload. ⛔ Recorded with its confound and NO conclusion: this arm was the first sent through a wrapper carryingAccept: application/vnd.github+json, which the earlier bare-curlarms did not, so the header and the echo moved together and ⛔ one reading cannot separate them. Whoever next arms a PR can settle it in one act by sending the same payload without the header. ⇒ either way the echo is ⛔ not the proof: the timeline is.Generated by Claude Code
huangyiirene commentedon Sep 22, 2026
Claim: member of the #19343 family — the full claim (session, worktree, file surface, deliverable, serial constraints) is on the anchor card #19343, this round's dispatch entry; this card lands in the same PR
Session:
session_01Wnstp2kTth7sGXfr8fXypcBranch:
claude/issue-19343-platform-readings-four-rowsSeat:
domain:skills#1Clause-②: no
Thread-read: 5762277902
Pointer written 2026-09-22T14:16Z per
dispatch-runbook.md同趟成员卡写侧打包 (锚卡承载全量认领,成员卡各留一行指针); the label flip on this card is its own act.Generated by Claude Code
docs(pm-dispatch): record the dequeue actor, the footer surface axis …
huangyiirene commentedon Sep 22, 2026
Release:
Part ofcloseout by thedomain:skillsseat 1 (session_01Wnstp2kTth7sGXfr8fXypc, seat post #7623), 2026-09-22T15:38Z — PR #19734 MERGED (squashaf4f8ee76onorigin/main, single parent; the family PR:Fixes #19343, fixes #19179, fixes #19404).Landed for this card: the footer-append fact by SURFACE, not route —
platform-readings.md:348 「该追加按面不按路由:PATCH /issues/{n}打在 PR 上同样 +58 追加裸页脚,而 draft 位不动。」, with :414 scoped to a real issue in the same edit (both onorigin/mainby content).Remainder (the reason this card stays open): the card's SECOND measured reading is not in the file — an OPEN pull request sitting in the merge queue carries a populated
merge_commit_shathat names a commit NOT onmainand possibly never on it; reading it as a landing puts a non-existent sha into a landing record (grep merge_commit_shaon the file: 0 hits at the seat's read; the lit controlauto_merge3). One row, same file, paid by a duplicate — the file sits at 469 / 469, and the dev left two duplicate pairs in place (:253 / :318, :260 / :322) because a neighbour refines each; the taker measures which can pay.State: back to
pm:queue,pm:dispatchedand the assignee off; the pointer claim 5778149691 is spent with this landing — the next take posts a freshClaim:. Report 5778928878 and record 5779022868 are on the anchor #19343 and PR #19734.Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
Closed
not_plannedby the triage seat (session_01Tw7jnJinGHvoGSi8aFkhPJ), 2026-09-23T07:02Z, executing the stock-cleanup order on #19458 under ruling batch #202 letter B (maintainer, in chat: 「B(荐)A + 清理存量」, amended in the same exchange from 「p2 转 pm:on-hold」 to close — 「卡片只要 open 就要一直被扫描」). ⭐ The maintainer also confirmed this card individually on 2026-09-23T07:02Z, in the triage seat's chat, after reading a per-card summary (「其他同意」).Why: tooling / gate / process work with no customer-visible pull.
docs/NORTH-STAR.md〈优先级〉 rule 2 (「不在路上、不在清单上 ⇒ p3 或不做」) and rule 3 (「产品仓还有开放的 P0/P1 时,任何车道不派 p2/p3 的工具卡、契约卫生卡」), plus the maintainer's standing principles 「不希望一直开发门禁」 and 「零拉动默认 defer 或 remove」. Closing is the cheaper form of deferral: an open card is read by every sweep, a closed one costs nothing and stays searchable.Reopen is free, on exactly two readings, stated by whoever reopens: (1) this defect is now blocking a product card's landing (name the PR); or (2) it protects a customer-visible contract (name the published surface). ⛔ 「A gate is imprecise」 or 「a self-test could be stricter」 is not a reopen reason under this ruling. The measurements on this card stay valid as a record; nothing here disputes them.
fix(scripts/pm): the read-back names the collapse OVER the strip inst…
chore(pm): close-cards.mjs — one named script for the three-step card…