/embed.json` + placement in `embed.js` |
| `_ask_inline.html`'s `styles()` | the CSS lives in `embed.js` |
| `FAVICON_LINK` string injection | `document.querySelector('link[rel~="icon"]')` |
**The fragments are still rendered by Jinja.** `embed.js` places what comes back
and never builds one — a second renderer in JavaScript would be the same bug
INV-1 exists to stop, in a new language. The payload also decides openness
(`open_marks`) and order, so the page has no opinion about either.
## The thing the contract got wrong, and the seam review caught
The payload first keyed `questions` by question key. **A single-question pick
normalizes to `questions: [{"key": None, …}]`** (`asks.normalize_ask`, the
`multi: False` branch), and `json.dumps` writes that key as the string `"null"`
— inventing a name that collides with a real key. Every one-question ask in the
fleet would have hit it, including the live `sindra-voice-1`. `questions` is a
LIST of `{key, html}` now; the key is nullable, and declaration order rides in
the format instead of leaning on object-key insertion order.
The cold contract panel could not have found this: it is a fact about
`booth/asks.py`, which an artifact-only reader never sees. Third time the seam
review has caught what the cold pass structurally cannot — see
[[2026-09-21-two-gates-are-complementary]].
## The live report that was already subtly broken
`dfa-concepts/index.html` writes `
The one asset that must survive
`. `_EL_RE` matched the **opening tag**
and replaced it, so the author's `.ask` wrapper class vanished, the heading was
orphaned and the `` went stray. Nobody filed a bug, because a page that is
95% right does not look broken.
`el.insertAdjacentHTML("beforeend", frag)` keeps the element and its contents
and puts the fragment inside. Verified live in a real browser: 5 author `.ask`
wrappers intact, 5 headings intact, 14 radios mounted inside them, zero console
errors. **The replacement is not just less fragile, it renders the operator's
own report more faithfully than the thing it replaced.**
## The cost, stated because it is real
The verbatim path used to work with **no JavaScript** — server-rendered ask, plain
form POST, HTML5 `form=` binding resolved at parse time. It needs the script now.
The operator's 2026-09-21 ruling accepts that; this entry records the consequence
so nobody meets it as a surprise. The never-invisible guarantee survives in a
weaker and still-true form through surfaces needing no script: the index card's
open-mark badge, and `/b//marks`.
## Anchor syntax
`data-booth-mark` is canonical (U2 made an ask one shape of mark).
`data-booth-ask` is a kept alias — 2 of the 4 live verbatim booths spell it that
way, in the operator's own reports, and the alias is one clause in one selector
string. The `` comment forms were **dropped, not ported**:
zero users across all 21 live booths, and a page that used one falls back to the
append path, so its ask still renders.
## Verification
431 tests (410 → 431). Live: all 21 booths 200, and each of the four verbatim
booths grew by exactly 46 bytes — `len(EMBED_SCRIPT_TAG)`, one append, nothing
else. Related: [[2026-09-22-the-browser-became-a-test-surface]],
[[2026-09-22-seven-of-seven-falsifiers]],
[[2026-09-21-regex-injecting-chrome]].