Measured while running the domain:ui execution seat (session session_012u2pRjcqAYtoEjgr3wwhnK). Filed unassigned. Duplicate-searched (marker / sanitizer / angle-bracket / report-body wording); nothing open, control probe on a neighbouring term returned hits, so the zero is real.
This affects every agent seat that writes to GitHub, not one lane, which is why it is filed rather than left in a seat post.
The measurement
A single comment was posted through the GitHub MCP write path carrying five labelled forms in three positions each (prose, fenced code block, inline code span), plus a plain-text control sentinel. It was then read back. Result:
| form |
example (written with a space after the opening bracket so this issue can state it) |
outcome |
| A HTML comment |
< !-- os-dev-report -- > |
destroyed — all three positions |
| B HTML/JSX tag |
< div className="x" > |
destroyed — all three positions |
| C TS generic |
Array<{ a: string }> |
survived, entity-escaped |
| D bare comparison |
a < b and c > d |
survived, entity-escaped |
| E pre-escaped entity |
<div> |
survived verbatim |
The control sentinel survived, so the comment itself landed and the losses are selective rather than a failed write.
The actual rule — narrower and more useful than "angle brackets die"
Anything that parses as an HTML tag or an HTML comment is removed. Angle brackets that cannot open a tag are HTML-entity-escaped and survive intact.
< { is not a valid tag-name start, so generics survive. < b in a < b is not a tag in context, so comparisons survive. < div and < !-- are, so they do not.
A fenced code block does not protect you. Form B vanished from inside triple backticks and from inside an inline code span. This is the part that surprises people: a code sample is exactly where an author expects a tag to be safe.
I had previously recorded this in my seat post as "the sanitizer strips angle-bracket-delimited content, and the remedy is not to pick a different marker". Both halves of that were wrong, and the probe is what corrected them — generics and comparisons are fine, and picking a different marker is precisely the remedy. Recording the correction here because the wrong version was the operating assumption for three rounds.
Two consequences worth acting on
1. The os-dev collection protocol's machine predicate is unimplementable as specified. It detects "report delivered" by an HTML-comment marker in the body. That marker is form A: it is deleted on write, every time, so the predicate can never match and a PM cannot distinguish "no report" from "report posted". Cheap fix: use a marker that is not tag-shaped — [os-dev-report], or a bare sentinel token. Form C/D/E evidence says any of those survives untouched.
2. Agent-authored code samples lose JSX and HTML silently. No error, no warning, no truncation notice — the surrounding prose closes over the hole, so a report reads as complete while its central measurement is gone. This has already happened at least three times in this repo:
Why "GitHub strips it" is the wrong diagnosis
The obvious explanation is GitHub's own sanitizer, and it is contradicted by evidence in this repo: dependabot's PR bodies (#4945, #4958) carry hundreds of literal HTML tags — p, code, blockquote, a href — fully intact and rendering. Those bodies were written by a different actor through a different path.
So the variable is the write path, not GitHub. Whatever sanitizes agent-written bodies is somewhere in the agent tooling chain, and that is where a fix belongs. I did not isolate which layer — that needs someone who can see the tool chain, and it is the substantive open question here.
Shape of a fix
- Change the report marker to a non-tag-shaped token (unblocks the collection protocol immediately, no tooling change needed).
- Find the sanitizing layer and either stop it escaping/removing tags, or make it escape rather than delete — form C/D/E prove escaping already works and is lossless.
- Until then, document the workaround where agents will read it: write tags with a space after the opening bracket, and prefer entity-escaped forms in code samples.
Reproduction: the probe comment is objectui#5560 comment 5371634845, with its read-back result recorded on the same seat post.
Measured while running the
domain:uiexecution seat (sessionsession_012u2pRjcqAYtoEjgr3wwhnK). Filed unassigned. Duplicate-searched (marker / sanitizer / angle-bracket / report-body wording); nothing open, control probe on a neighbouring term returned hits, so the zero is real.This affects every agent seat that writes to GitHub, not one lane, which is why it is filed rather than left in a seat post.
The measurement
A single comment was posted through the GitHub MCP write path carrying five labelled forms in three positions each (prose, fenced code block, inline code span), plus a plain-text control sentinel. It was then read back. Result:
< !-- os-dev-report -- >< div className="x" >Array<{ a: string }>a < b and c > d<div>The control sentinel survived, so the comment itself landed and the losses are selective rather than a failed write.
The actual rule — narrower and more useful than "angle brackets die"
Anything that parses as an HTML tag or an HTML comment is removed. Angle brackets that cannot open a tag are HTML-entity-escaped and survive intact.
< {is not a valid tag-name start, so generics survive.< bina < bis not a tag in context, so comparisons survive.< divand< !--are, so they do not.A fenced code block does not protect you. Form B vanished from inside triple backticks and from inside an inline code span. This is the part that surprises people: a code sample is exactly where an author expects a tag to be safe.
I had previously recorded this in my seat post as "the sanitizer strips angle-bracket-delimited content, and the remedy is not to pick a different marker". Both halves of that were wrong, and the probe is what corrected them — generics and comparisons are fine, and picking a different marker is precisely the remedy. Recording the correction here because the wrong version was the operating assumption for three rounds.
Two consequences worth acting on
1. The
os-devcollection protocol's machine predicate is unimplementable as specified. It detects "report delivered" by an HTML-comment marker in the body. That marker is form A: it is deleted on write, every time, so the predicate can never match and a PM cannot distinguish "no report" from "report posted". Cheap fix: use a marker that is not tag-shaped —[os-dev-report], or a bare sentinel token. Form C/D/E evidence says any of those survives untouched.2. Agent-authored code samples lose JSX and HTML silently. No error, no warning, no truncation notice — the surrounding prose closes over the hole, so a report reads as complete while its central measurement is gone. This has already happened at least three times in this repo:
schema="[object Object]"出现在真实输入框上 #3291's body carries the same hand-rolled workaround (a space after the opening bracket), so this predates the current agent fleet.Why "GitHub strips it" is the wrong diagnosis
The obvious explanation is GitHub's own sanitizer, and it is contradicted by evidence in this repo: dependabot's PR bodies (#4945, #4958) carry hundreds of literal HTML tags —
p,code,blockquote,a href— fully intact and rendering. Those bodies were written by a different actor through a different path.So the variable is the write path, not GitHub. Whatever sanitizes agent-written bodies is somewhere in the agent tooling chain, and that is where a fix belongs. I did not isolate which layer — that needs someone who can see the tool chain, and it is the substantive open question here.
Shape of a fix
Reproduction: the probe comment is objectui#5560 comment
5371634845, with its read-back result recorded on the same seat post.