The first TNDM deck came from a screenshot gallery. It exercises every parser frame type and has a real feedback loop to close; the parsing rules are not gallery-specific. See md-parser.
flowchart LR A["Source gallery Markdown<br/>2026-08-20 feedback tour"] -->|POST deck import| B["Deck qwizz-2026-08-20<br/>76 sections · 323 frames · 320 images"] B --> C["Tandem session<br/>review, verdicts and annotations"] C -->|GET export.md| D["Decision export<br/>YAML stats + decision bullets"] D -. not merged yet .-> E["Source gallery<br/>route callouts + Feedback log"] E -->|re-import same deck id| B
Source gallery
| Property | Measured value |
|---|---|
| Source | /home/loca/dev/wrdp/q5vault/audits/qwizz/2026-08-20-feedback-tour.md |
| Published route | https://wiki.wrdp.loca.zone/audits/qwizz/2026-08-20-feedback-tour; HTTP 200 checked 2026-08-20 |
| Frontmatter title | 🎞️ QuizWizz UI/UX Feedback Tour — Complete Shot Gallery |
| Release status | releaseEligible: false (2026-08-20-feedback-tour.md:7); importing or reviewing this bench-local evidence is not a release decision. |
| Capture | Every reachable QuizWizz surface, persona and state on 2026-08-20: 315 screenshots plus 5 contact-sheet boards, grouped by wave and route (2026-08-20-feedback-tour.md:10) |
| Source structure | Deck interpretation |
|---|---|
| No h1 | Deck title comes from frontmatter (src/lib/mdframes/mdframes.test.ts:101-103). |
| 11 h2 sections | Tour yamlsum, Coverage, Blocking defects found during capture, Boards, waves A–E, Feedback log, Method & residue (src/lib/mdframes/mdframes.test.ts:39-51,112-114). |
| 65 h3 route sections | <route-id> — <surface>, such as g01 — landing/front page (2026-08-20-feedback-tour.md:88). |
| Route body | URL in backticks, image plus immediate <sub> metadata, then callouts (2026-08-20-feedback-tour.md:88-105). |
| Warning and note callouts | Findings in this route carries QA findings; Feedback — <route-id> carries the tour-note placeholder (2026-08-20-feedback-tour.md:1495-1499). |
A source pair at 2026-08-20-feedback-tour.md:92-93:

<sub>g01-d.png · desktop 1280x900 · fold</sub>The <sub> becomes frame sub and splits on · into tags: ["g01-d.png", "desktop 1280x900", "fold"] (src/lib/mdframes/index.ts:440-450). A trailing ⚠️ finding adds the frame’s finding badge (src/lib/mdframes/index.ts:451-457; source example at line 124).
| Coverage | Count |
|---|---|
| Wave A / B / C / D / E | 141 / 13 / 130 / 8 / 23 shots |
| Routes | 65 |
| Clean / finding verdicts | 250 / 65 |
| Deliberately absent shots | 5: two dead preview tabs, one notice without mutation control, one unreachable import notice, one nonexistent state (2026-08-20-feedback-tour.md:36-51) |
Import call
export TNDM_TOKEN=$(cat /home/loca/dev/tandem-audit/.api-token)
curl -sX POST https://tndm.loca.zone/api/decks/import \
-H "Authorization: Bearer $TNDM_TOKEN" \
-H 'content-type: application/json' \
-d '{"md_path":"/home/loca/dev/wrdp/q5vault/audits/qwizz/2026-08-20-feedback-tour.md","copy_from":"/home/loca/dev/wrdp/q5vault/assets/qwizz-tour/2026-08-20","id":"qwizz-2026-08-20"}'The bearer header is required since 2026-08-21. The original 2026-08-20 import was anonymous because no gate then accepted or required a credential; api owns the current contract.
copy_from makes the deck self-contained. Pointing at the published Quartz URLs would bind it to whichever frozen dist-<epoch> an explicit production build had installed. Import copied 315 shots and 5 boards into /home/loca/tndm/decks/qwizz-2026-08-20/assets/{shots,boards}: 320 files, matching the source count, 0 missing. Sources were rewritten to deck routes such as /api/decks/qwizz-2026-08-20/assets/shots/g01-d.png (src/lib/server/importer.ts:227-237; disk recounted 2026-08-20).
Resulting deck — measured 2026-08-20
| Deck shape | Value |
|---|---|
| Sections | 76: 11 level 2, 65 level 3, no level 1 |
| Frames | 323: 320 image, 2 table, 1 code |
| Images | 315 under /shots/, 5 under /boards/ |
| Frame badges | 65 finding |
| Section callout findings | 139 |
| Copied assets | 320, with 0 missing |
The table frames are Coverage and Blocking defects found during capture; the code frame is the Tour yamlsum fence, tagged yaml (src/lib/mdframes/index.ts:386-388, src/lib/mdframes/mdframes.test.ts:93-98). Default parsing ignores paragraph prose, so 1618 source lines become 323 reviewable frames.
Why the fixture says 321 images
| Measure | Frozen fixture | Live deck |
|---|---|---|
| Identity | MD5 a15fb4f0ffb6d07e8256402563193d15; 1619 lines | Re-measured per import |
| Sections | 76; 65 at level 3 | 76; 65 at level 3 |
| Image frames | 321 | 320 |
| Shot / board sources | 316 / 5 | 315 / 5 |
finding badges | 66 | 65 |
Image sub | Non-empty on all 321 | Non-empty on all 320 |
The frozen fixture still contains v01-d-p02-player-intro.png and its finding chip at src/lib/mdframes/fixtures/qwizz-tour.md:1480-1481. The live gallery withdrew it: cleared storage opens directly on question 1, so the claimed intro state does not exist (2026-08-20-feedback-tour.md:51,1493-1494). This one-frame difference is intentional. Fixture constants defend measured ground truth and are never re-baselined (src/lib/mdframes/mdframes.test.ts:1-10,54-84).
What the reviewer does
- Choose a route in the rail. H2 headings form groups; h3 headings form rows.
Tour yamlsum,Coverage,Blocking defects found during captureandBoardshold the non-wave frames. Wave headings hold frames in child routes, so a group badge sums header and rows (src/lib/components/Rail.svelte). - Focus a frame control, then assign
keep,recaptureorkill; add anote,taskorscribble; mark a route done when appropriate. quickstart owns the full keymap and operator flow. - Read counters honestly.
Feedback logandMethod & residuehave no frames; seven sections are frame-empty and do not enter the progress ring (src/routes/s/[sessionId]/+page.svelte). - Use stable targets. Section ids slug headings:
g01 — landing/front pagebecomesg01--landingfront-page; its first frame isg01--landingfront-page/1. Because frame ids contain/, cards are resolved by element id rather than a CSS selector.
Both callout types enter section.findings[], so its 139 entries mix QA findings with _(awaiting tour notes)_ placeholders. Live route g01 contains only that placeholder. The QA signal is the 65 frame-level finding badges. Since the 2026-08-21 polish pass, the rail find column counts finding-badged frames and amber means outstanding unruled finding frames; section callout text remains available in the section details (src/lib/mdframes/index.ts:288-335).
Export and merge back
Review status on 2026-08-21: the first tandem audit is underway. Nothing has been merged back into the source gallery yet.
GET /api/sessions/<sessionId>/export.md returns text/markdown; charset=utf-8 as tandem-<sessionId>.md (src/routes/api/sessions/[id]/export.md/+server.ts:12-17). Its fenced YAML header records deck, title, session, generated, duration, events_reported, by_kind, frames_touched and sections_done; then ## Tandem audit <sessionId> — <date> introduces one line per decision (src/lib/server/export.ts:108-133).
| Export behaviour | Result |
|---|---|
| Decision bullets | note, task, verdict, speech, scribble |
| Non-bullets | nav and status are transport chatter; say is agent speech; route_done contributes to sections_done. |
| Bullet shape | Kind and frame or section target, then verdict, text and tags on one line (src/lib/server/export.ts:49-70). |
| Scribble | Relative [scribble](scribbles/<file>); copy the PNG from DATA_DIR/sessions/<id>/scribbles/ into the gallery asset tree and rewrite the link (src/lib/server/export.ts:56-59). |
| Human frame reference | Export target is a deck id such as g02--builder-craft/17; splice the shot filename from the frame’s first tag when needed. |
| Re-import | Importing the same deck id refreshes frames and captions but leaves existing tandem sessions untouched (src/lib/server/importer.ts:255-261). |
The merge target is ## Feedback log at source line 1601. On 2026-08-20 it held one bullet: - 2026-08-20 — gallery published, tour ready for the first pass. at line 1605. The gallery instructs reviewers to write per-route feedback first, then promote accepted or rejected notes and applied decisions as dated, one-bullet entries (2026-08-20-feedback-tour.md:12). That promotion has not happened yet.