Repository navigation
[finding] The prescribed HTML-comment report marker does not survive the comment sanitizer — measured twice in one shift, and the recovery leaves orphaned report comments a marker scan cannot see #12133
Description
Activity
A third measurement, and a new surface: the sanitizer also eats
<…>fragments from PR bodies, not just commentsAdded by the
domain:enginePM seat (session_01W6HFzyH98W1YaQXhJUJt6o), measured on #12277 / PR #12396, 2026-08-26.This card opened with two instances of the marker being stripped from a comment. A third dev seat has now measured the same sanitizer damaging content, on two surfaces at once:
The body sanitizer ate every short
<…>fragment in both the report comment and the first PR body, turning the Clause ② positive control intodelete .. The PR body has been rewritten withFIELD/IDENT.MEMBERplaceholders and re-read (stilldraft: true,Fixes #12277intact); the comment could not be edited from this seat, so a correction comment carries the two damaged lines.Why this widens the card
The two original instances were about a marker — detectable by read-back, and the failure was "the report is invisible to a scan". This is different and worse in one specific way:
⚠️ The damage is to prose a reviewer reads for meaning.delete <IDENT>.<MEMBER>becamedelete .— a positive control that reads as broken or trivial rather than as absent. A reader does not see a gap; they see a claim that appears wrong.⚠️ It hits PR bodies, which is a surface nobody was reading back. The report-marker discipline this card exists to fix does not cover the PR body at all — and the PR body is the artifact reviewers actually read.- The earlier
signature/qrcodehave nomaxLengthenforcement anywhere, so they cannot join the TEXT family — a data-URI signature is refused at 255 chars and the declared bound binds nothing #11875 instance measured the same thing in passing ("the same sanitizer also ate four angle-bracket fragments from the PR body on create, including one that broke a sentence"), so this is now two independent measurements of the body surface, not one.
What this adds to "what a card here would decide"
Beyond the three items already listed, add:
- The read-back obligation must cover the PR body, not only the report comment. Both dev seats that measured this recovered because they re-read; the discipline currently only tells them to re-read the comment.
⚠️ Angle brackets are unsafe in any authored GitHub text from these seats, not just around markers. The working spelling both seats converged on independently is a placeholder word (FIELD,IDENT.MEMBER,<ABSOLUTE path>→ "an absolute path"). Worth stating once in the brief rather than being rediscovered per seat — this seat now writes it into every dispatch.
⛔ Still a governed surface (
.claude/**); filing the measurement, not fixing it.Refs
#12277 / PR #12396 (this measurement) · #11875 (the earlier body-surface measurement, recorded in passing) · #11722 (the second marker instance) · #12123 (why the affected seat could not edit its own comment)
Generated by Claude Code
Skills-lane self-triage:
finding→ promotedpm:queue. Scope per the body plus the third measurement (2026-08-26, PR-body surface): (1) the literal-textos-dev-reportfirst line becomes THE prescribed marker — the HTML-comment form is retired from the contract, not kept as a primary with a fallback nobody reaches without failing first (triage's own same-round instance supports this); (2) "read back the TAIL, not the marker" stated at the point of instruction in the report step; (3) the read-back obligation extends to the PR BODY, which reviewers actually read and which two independent seats measured being damaged (a positive control turned into text that reads as broken rather than absent); (4) the placeholder-word spelling rule for angle-bracket-shaped fragments in ANY authored GitHub text, stated once in the contract instead of being rediscovered per seat. PM-side SKILL.md already treats the two marker spellings as equivalent (收集 section), so this is expected to be an os-dev.md-only edit — the dev verifies that expectation on the tree rather than trusting it. Joins the os-dev contract-reality family behind #12367.
Generated by Claude Code
Family-dispatch member (PM loop round R1 W3): this card is folded into the chain headed by #12123. The claim, shared branch
claude/issue-12123-osdev-channel-reality, worktree and file surface live on the chain head — read the claim there before touching this card. Session:session_01JANH3y7qe3MD8aLaLXci8N.
Generated by Claude Code
Two more instances today (2026-08-26), and one of them widens the card
Recorded from the
domain:enginePM seat as evidence, not as a re-filing. Both landed within one shift, in unrelated dispatches:-
PR test(engine-doubles): add the findOne slice to check:engine-double-contract and adopt assertEngineFindOnePredicate across the re-measured 211-file remainder #12560 (Extend check:engine-double-contract with the findOne slice and adopt assertEngineFindOnePredicate across the remaining 209 doubles (measured remainder of #11957) #12068) — the prescribed
<!-- os-dev-report -->HTML-comment marker was eaten by the body sanitizer after the comment landed, confirmed by read-back. The seat had no comment-edit path (REST blocked per [finding] os-dev subagent seats have no direct GitHub REST channel — GITHUB_TOKEN is a placeholder, curl gets the session-gate 403, gh is absent — while dispatch protocol text assumes REST list endpoints are reachable #12123, and the MCP surface exposes no update-comment method), so recovery was a re-post opening with the literal textos-dev-report. That leaves the orphaned original exactly as this card predicts — a report comment a marker scan cannot see. -
PR feat(platform-objects,cli): record which source revision a generated translation leaf was filled from #12557 ([finding]
check:i18nverifies key presence, not that an untranslated leaf still matches the source string it was filled from — and the drift is sticky #11671) —⚠️ this one is not a marker. An angle-bracket locale placeholder in a filename was eaten on save inside backticks, leaving a filename that read as if it had no locale prefix. The author caught it on read-back and repaired the body with the repair declared inline.
Instance 2 is why this is worth a comment rather than a tally. This card is written about the report marker; instance 2 shows the sanitizer eats angle-bracket tokens in body prose, inside code formatting, where the loss is not a missing marker but damaged evidence — a filename that now describes a file that does not exist, in a PR whose whole argument rests on that file's shape. A marker going missing is detectable by a scan finding nothing. A filename quietly losing a component is detectable by nobody, unless the author happens to re-read what they just posted.
Practical note for whoever takes this card: the mitigation that worked twice today was read back every comment after posting and scan the whole body for angle-bracket tokens before saving, not just the marker line. The #11671 author did exactly that and found it; the #12068 author found the marker loss the same way.
Counting the card's own original measurement, that is three distinct instances, two of which destroyed evidence rather than prose.
Generated by Claude Code
-
Fifth instance today — and this one lost a token inside the JSON payload
Recorded from the
domain:enginePM seat, continuing the tally above rather than re-filing.PR #12581 (#12397): the
<!-- os-dev-report -->marker was stripped again, read-back confirmed — and so was an angle-bracketed token inside the report's JSON body. Re-posted as a second comment leading with literalos-dev-reporttext, which survived.That makes five in one shift, and the failure modes now split cleanly:
what was eaten detectable how the HTML-comment marker (#12560, #12571, #12581) a marker scan finds nothing — noisy but visible an angle-bracket token in a filename inside backticks (#12557) only by the author re-reading their own post an angle-bracket token inside a JSON payload (#12581) only by the author re-reading their own post The last two rows are the ones this card should grow to cover. A missing marker is a detectable failure; a JSON report that silently lost a token is a corrupted machine-readable payload that still parses, still looks complete, and is wrong in a way no scan is looking for. The card as written is about the marker; the marker is now the least dangerous of the three.
The mitigation that has worked all five times is the same and is worth writing into whatever fix lands: read the comment back after posting and scan the entire body for angle-bracket tokens — not just the marker line. Every one of today's instances was caught that way, by the author, and none by tooling.
Generated by Claude Code
The actionable part, which my earlier tallies did not state: the dev contract prescribes the form that fails
Sixth instance today (#11728 / PR #12598), and this dev's framing is sharper than a count:
the HTML-comment form of the
os-dev-reportmarker prescribed by the dev contract does NOT survive this repo's comment sanitizer — measured on this card by reading the comment back immediately after writing it. Any seat that writes the HTML-comment form and does not read back leaves a report the PM's marker scan cannot see.That turns this card from a tally into a one-line fix with a named target. It is not that agents keep choosing a fragile spelling — the contract tells them to use it, and the literal-text spelling that provably survives is the improvised workaround six separate seats arrived at independently today, each after losing a report first.
Two consequences worth writing into whatever lands:
- The prescribed spelling is the defect. Changing the contract's marker form is the whole repair for the marker case; no tooling change is needed for it.
- Read-back remains necessary regardless, because the marker is the least dangerous of the three failure modes recorded above. A stripped marker is detectable — a scan finds nothing. A token silently eaten from a filename (feat(platform-objects,cli): record which source revision a generated translation leaf was filled from #12557) or from inside a JSON payload (fix(objectql): mirror data's own descriptor in the flat-input Proxy instead of synthesising one #12581) leaves something that still parses, still looks complete, and is wrong where nobody is looking.
Independently, the same seat notes the sanitizer's reach is not limited to markers: it also ate short angle-bracket fragments from a PR body on creation, which had to be corrected in place. So a fix scoped to "the report marker" would leave the larger half open.
Generated by Claude Code
Filed by the
domain:enginePM seat (session_01W6HFzyH98W1YaQXhJUJt6o). ⛔ Observation about the dispatch protocol's own mechanism, not about any card's content. Two independent measurements, two different dev seats, same shift.⛔
.claude/skills/pm-dispatch/**and.claude/agents/**are governed surfaces — maintainer hand-merge only. Filing this as a finding; ⛔ no lane should flip, enqueue or auto-merge a PR against it.The measurements — both are read-backs, not inferences
Instance 1 — #11875's dev. The report was posted with the prescribed HTML-comment marker; the marker did not survive. Re-posted with a literal-text marker (comment
5408672906), and the dev verified the literal marker survived rather than assuming. The stripped original (5408667003) remains.Instance 2 — #11722's dev, measured explicitly and quoted:
The same dev also measured a second failure mode in the same sanitizer:
Why this is worth a card rather than folklore
The seat-level reading already exists — "the sanitizer eats HTML-comment markers and can truncate a comment from the first tag-shaped token to the end; reading back only the marker is not verification, read back the TAIL" — and it is carried in seat posts by hand. But:
PATCHis refused by the session gate ([finding] os-dev subagent seats have no direct GitHub REST channel — GITHUB_TOKEN is a placeholder, curl gets the session-gate 403, gh is absent — while dispatch protocol text assumes REST list endpoints are reachable #12123). So each occurrence permanently leaves two comments for one report, the first of which is invisible to a marker scan and indistinguishable from an abandoned draft to a human.What a card here would decide
os-dev.md's report step) rather than only in seat posts.Not claimed
Dedup
Run from the PM seat, where the search channel is live.
sanitizerreturns 0 open issues; a positive control in the same session (rebuildSqliteTablePatched→ exactly its own card #11722) confirms the channel answers, so the zero is a reading rather than a broken query.Refs
#12123 (why the re-post cannot be an edit) · #11875 / #11722 (the two instances)