Public: anyone can read this; the crew can change it.
Every outside and from-app report reaches a crew brief inside the fence, whoever wrote it #11797
Check · Review · Land · Live done — Landed and live in production.
A crew brief now fences the body of every outside report and from-app note, whoever filed it. The `outside` / `from-app` label or the title mark is enough. Before this, `src/crew/brief.ts` printed the body as plain text, or indented it when a reader wrote it. Either way, the line "the text inside the fence below" pointed at a fence that wasn't there. That included a report the owner or a writer ha…
shipped production is serving it deploy d20ce1b
A crew brief now fences the body of every outside report and from-app note, whoever filed it. The outside / from-app label or the title mark is enough. Before this, src/crew/brief.ts printed the body as plain text, or indented it when a reader wrote it. Either way, the line "the text inside the fence below" pointed at a fence that wasn't there. That included a report the owner or a writer had accepted.
What changed
src/crew/brief.ts: the outside and from-app checks are now worked out once, asoutsideandfromApp. The same two values pick the warning paragraphs and decide whether the body goes throughfenced(body, "text").- A reader's outside report keeps its "Written by … a reader" preamble. Its body is now fenced as well as warned about, instead of only indented.
- An ordinary issue is unchanged: its body is still printed plainly as the task.
- The body can't close the fence early:
fenced()makes its fence one backtick longer than the longest run of backticks in the body. So a body holding its own fenced block, or a fake closing fence, stays inside.
Tests
test/brief-injection.test.tshas a case for each kind (outside and from-app), filed by the owner and by a writer. Each kind is also tested once by label and once by title mark alone, which makes 8 cases.- A ninth case covers a reader's outside report.
- These cases use a hostile body that holds a closing fence, a fake heading and an order. Each checks that the body appears in exactly one fenced block and that the fake heading never appears outside a fence.
- All nine fail against main's
brief.tsand pass with this change. - A control case checks that an ordinary writer's issue is still printed plainly and not fenced.
Checks run
bun scripts/gate.tsandbun x tsc --noEmitpass.scripts/fast.tsnamed 368 files (about 31 minutes) for this diff. Instead I ran the 38 test files that use the brief: 453 pass, 0 fail.
Not done: the fenced block that report acceptance already writes into the issue body is left alone. The brief now wraps the whole body in a longer fence, so that inner block stays inside.
🤖 Generated with Claude Code
Outside and from-app bodies are now fenced by kind (label or title mark), whoever filed them, and a reader report is fenced as well as indented. The two warning paragraphs that say "inside the fence below" are the only ones that say it, and they now share the same outside/fromApp values that decide the fence, so the words are true. fenced() lengthens the fence past any backtick run, and the tests cover the hostile body. Ordinary issues are unchanged. No UI surface, so no TUI or docs needed. Next two: (1) comments on an outside/from-app issue by non-writers are only indented; consider fencing them too. (2) The label-only and title-only title tests do not assert the "inside the fence below" sentence; add it so box 2 is pinned for both paths.
A crew brief now fences the body of every outside report and from-app note, whoever filed it. The
outside/from-applabel or the title mark is enough. Before this,src/crew/brief.tsprinted the body as plain text, or indented it when a reader wrote it. Either way, the line "the text inside the fence below" pointed at a fence that wasn't there. That included a report the owner or a writer had accepted.What changed
src/crew/brief.ts: the outside and from-app checks are now worked out once, asoutsideandfromApp. The same two values pick the warning paragraphs and decide whether the body goes throughfenced(body, "text").fenced()makes its fence one backtick longer than the longest run of backticks in the body. So a body holding its own fenced block, or a fake closing fence, stays inside.Tests
test/brief-injection.test.tshas a case for each kind (outside and from-app), filed by the owner and by a writer. Each kind is also tested once by label and once by title mark alone, which makes 8 cases.brief.tsand pass with this change.Checks run
bun scripts/gate.tsandbun x tsc --noEmitpass.scripts/fast.tsnamed 368 files (about 31 minutes) for this diff. Instead I ran the 38 test files that use the brief: 453 pass, 0 fail.Not done: the fenced block that report acceptance already writes into the issue body is left alone. The brief now wraps the whole body in a longer fence, so that inner block stays inside.
🤖 Generated with Claude Code
Closes #11768