# W6 gate — releases#331 (#337, #64, #340), core PR #272 @`0cb81a8e`

**LANDED.** `git push origin 0cb81a8e:refs/heads/main` → `02d024c4..0cb81a8e`; `ls-remote` main =
`0cb81a8efcc5289c625c1d8771a86e158d3716de`; PR #272 **MERGED** with
`mergeCommit.oid == headRefOid == 0cb81a8e`. Tested == merged. No `gh pr merge` verb was used.

## Subject, checked before any green was trusted

- CI run 36036829076 `headSha` = `0cb81a8e` = PR `headRefOid`. The green belongs to these bytes.
- 4 ahead, 0 behind `origin/main` (`02d024c4`) — a true ff candidate, no rebase needed.
- The earlier run on `fe81540c` is **CANCELLED**, superseded by the fix push. A cancelled run is a
  labelled hole: it proved nothing either way and was not counted.

## The finding this gate exists for

`#340`'s first head rendered the adapter changelog with
`Parser::new_ext(markdown, Options::all())` + `push_html`, **no filtering**, and served it
`text/html; charset=utf-8` from the node's own origin. Verified in the pinned crate's source
rather than asserted: `pulldown-cmark-0.13.4/src/html.rs:122` is
`Html(html) | InlineHtml(html) => self.write(&html)` (raw passthrough), and `:349` writes the
link href through `escape_href`, which escapes characters and does **not** filter schemes.

Adapter-supplied markdown reaching a same-origin served page is **stored XSS**. The boundary
argument is what makes it a refusal rather than a nit: installing an adapter is a local trust
decision, but this page is served to whoever can reach the node — an operator browsing a PEER's
pages runs the adapter author's script in an origin that never installed it.

Fix at `0cb81a8e`, re-read at gate: `Html`/`InlineHtml` → `Event::Text` (escaped by the
renderer); link and image destinations default-deny to `#` unless relative, http, https or
mailto, judged after folding ASCII whitespace/controls and case but **returning the original
URL** when safe, so the fold cannot corrupt a legitimate link; options narrowed to
`TABLES|STRIKETHROUGH|TASKLISTS`, which also drops heading attributes and footnotes; CSP
`default-src 'none'; style-src 'unsafe-inline'` on the response. No new dependency.

I checked the one vector the fix does not touch: a fenced block's info string reaches
`class="language-…"`, and the renderer puts it through `escape_html` (`html.rs:266`). Not an
injection point. Protocol-relative `//host/x` stays live and should — it is an http(s) link.

## Arms

| leg | result |
|---|---|
| compile gate — `cargo check --workspace --all-targets` | rc 0, 2m38s |
| `spt-runtime` lib units | 130 passed, 0 failed |
| the two security units, run BY NAME | `changelog_render_is_inert_against_hostile_markdown` ok, `changelog_destination_scheme_is_default_deny` ok (8 changelog tests, 122 filtered out) |
| `spt-daemon --test webserve_e2e` | 6 passed, incl. `an_installed_adapter_changelog_is_rendered_and_served` |
| `traceable-reqs check` | rc 0 |
| CI 36036829076 | 6/6 green, both self-hosted unit legs |

Rig: `.worktrees/gate-w6-0cb81a8e` detached at the head, own pool claimed from inside it
(`claim_rc 0`, lane `gate-w6-0cb81a8e`). Writer census 0/0/0 before and after — the box was
genuinely quiet for these legs, read BEFORE launching rather than reported afterwards.

A pass count is not evidence that the tests you care about exist: the two security units were
re-run **by name** precisely so the 130 could not stand in for them.

## Builder credit, recorded because it corrected me twice

todlando's reading of the apply path beat mine twice in one lane. (1) REQ-NOW-SIGNAL-UPDATE-DIVULGE
said the apply record is written by "the daemon pump path"; the pump only ever stages, so that
premise was false and the daemon-side writer is the broker trial promotion — my wording was
replaced in the same commit. (2) On W7 he caught that promotion reads `AppliedPending` and so runs
only AFTER a swap, while `apply_staged` has no daemon-internal caller at all (both call sites are
`crates/spt/src/cli.rs:9981`/`:9983`) — so "auto-apply = the promotion path" would have shipped a
gap into the W7 mint.

He also proved the CSP assertion red on request (`if false` around the header insert → 5 pass /
1 fail at the CSP assert, status and content-type asserts above it still passing → restored →
6/6). An assertion nobody has seen fail is zero information.

## Teardown, measured

Pool before removal: apparent **10,219,069,949**, allocated **10,252,575,744**, escaped **0
inodes / 0 B** — a **FORCED** zero, population captured: 388 files at `nlink>1`, every link inside
the tree.

Free-space delta over the teardown: **+10,282,250,240**, against an expected 10,252,575,744 —
**+29,674,496 B more freed than predicted (+0.29%)**, with a 0-writer census on both sides. The
gap is not unexplained and gets no invented mechanism: **I measured only `target/` but removed the
whole rig**, so the rig's source checkout (~29.7 MB, the right order) is reclaim the prediction
never included. The expected-reclaim figure must cover everything the `rm` takes, not just the
pool.

`git worktree remove` first failed `Permission denied` — my own shell's cwd was still inside the
rig, the Windows handle pin todlando hit on the W5 teardown and solved the same way. Moving out
and retrying cleared it; `prune` then left 44 worktrees.
