OUROBOROS
the loop that watches itself being built
the brief: build the loop
so we pointed the loop at itself
an app whose only content is its own build — 15 iterations, every failure the checker caught, every lesson it learned, checkable down to the commit.
every arc below is one iteration of the loop that built this page — click one for its story, or press play to replay the whole build
green = banked · red rim = failures caught, then fixed
maker claude (spec + judge) · codex (implement)
checker testsprite cli — cloud tests against this live page
verdicts 15 banked · 7 caught & fixed · none hidden
lessons learned 8
ITERATION LOG
- #15passthe invitation & the trophy — a prominent 'start the briefing' CTA, the shareable Loop Card (download PNG), and Failure Fossils (the exact broken state, preserved) — broke: the checker caught two a11y regressions: the CTA's aria-label masked its visible invitation (L7 again), and the Loop Card's text was SVG-only, invisible to the a11y tree — fixed: CTA accessible name now matches its visible text; the Loop Card gained an sr-only text layer (L8) — decision recorded: content-SVG needs a text equivalent
- #14passthe presentation layer — Judge Mode (press J: a self-narrating briefing climaxing in the loop auditing its own checker), the ring's glow, and the hero that states the idea
- #13passkeyboard shortcuts overlay + full keyboard nav (the a11y capstone) — broke: the 'press ? for shortcuts' hint's aria-label overrode its visible text, hiding the '?' from the a11y-tree-reading cloud tester — fixed: removed the masking aria-label so the visible text is the accessible name (L7); rerun agent verdict PASS
- #12passfailures-only filter — isolate the caught-failure iterations across ring, log, and stats
- #11passdeep-linkable iterations — ?i=N opens a story card + copy-permalink button
- #10passtrust audit — hostile agent review turned into committed proof — broke: greens under-evidenced (only failures had committed bundles), ring hid its failures, stale card on scrub, sub-AA contrast, CI freshness unproven — fixed: run histories committed for all 8 tests, failure-rim viz + audit trail table, stale-selection clear, contrast raised, SHA-gated CI — full suite green against the exact commit
- #9passgrowth regression — intro scaled with data and hid the ring's controls — broke: at 8 iterations the draw-in left arcs invisible 3+ seconds; agent indexed mid-intro and found no clickable ring, then missed SVG-child controls intermittently — fixed: intro capped at a 0.9s total budget (L6) + controls hardened into real HTML button hit-targets (L1 update); agent verified 4/4
- #8passpolish — OG meta, favicon, footer, hook line, mobile pass (5 real bugs fixed)
- #7passchecker evidence inside story cards — failure-bundle excerpts — broke: tester clicked the replay diamond ('Seek to iteration 2') instead of the ring arc — look-alike controls — fixed: accessible names diverged + plan names the widget type (L5); rerun 17/17
- #6passharness cycle diagram — WRITE→VERIFY→BANK with the fail→LESSON loop — broke: 11px 'pass' connector label unreadable in the tester's screenshots — fixed: labels raised to 13.5px weight-500 (L4); rerun verified the label
- #5passlearning curve — stacked run bars + cumulative lessons step-line — broke: checker returned status 'blocked' while its own conclusion said PASS with all steps green — fixed: verdict recorded from the evidence; platform discrepancy reported upstream
- #4passflight-recorder replay — scrub and replay the loop's own history
- #3passmotion tokens + GSAP ring draw-on intro — broke: over-strict test assertion: orbit dot must visibly move — flaky under reduced-motion cloud browsers — fixed: plan refined to settled end-state assertions (L2); app unchanged
- #2passinteractive ring — click a segment for that iteration's story card — broke: ring arcs invisible to the testing agent — svg role=img flattened the a11y tree, segments not focusable — fixed: real accessible controls: tabIndex=0, Enter/Space handler, role=img removed
- #1passbaseline instrument panel (ring + stats + iteration log)
LEARNING CURVE
| Iteration | Passing runs | Failing runs | Cumulative lessons |
|---|---|---|---|
| Iteration 1 | 1 | 0 | 0 |
| Iteration 2 | 1 | 1 | 1 |
| Iteration 3 | 1 | 1 | 2 |
| Iteration 4 | 1 | 0 | 2 |
| Iteration 5 | 1 | 0 | 3 |
| Iteration 6 | 1 | 1 | 4 |
| Iteration 7 | 1 | 1 | 5 |
| Iteration 8 | 1 | 0 | 5 |
| Iteration 9 | 1 | 2 | 6 |
| Iteration 10 | 8 | 0 | 6 |
| Iteration 11 | 1 | 0 | 6 |
| Iteration 12 | 1 | 0 | 6 |
| Iteration 13 | 1 | 1 | 7 |
| Iteration 14 | 1 | 0 | 7 |
| Iteration 15 | 1 | 1 | 8 |
- L1Clickable SVG parts need role=button + tabIndex=0 + key handler, and the ancestor svg must not carry role=img (it flattens the subtree to presentational).iteration 2
- L2Never cloud-assert continuous ambient motion; assert the settled end-state. Decoration animation is progressive enhancement, verified locally.iteration 3
- L3Audit the checker's verdict against its observations: a status flag that contradicts its own evidence gets one fresh run, then record what the evidence shows and report the discrepancy.iteration 5
- L4Meaning-carrying labels in data graphics render at >=13px SVG (720 viewBox): if it's only legible because you know what it says, it isn't legible.iteration 6
- L5Plan steps must name the widget type and exclude same-entity look-alikes; accessible names for actions (Seek to...) and reveals (Open story card...) should diverge.iteration 7
- L6Cap the total duration of data-driven entrances (budget / item count, never per-item x count); interactive controls must be visible within ~1s no matter how much the data grows.iteration 9
- L7A control whose visible text is the information must not carry an aria-label that omits it — the label wins in the a11y tree and hides the text from agents and screen readers. Omit it or mirror the info. (Third a11y lesson: L1 hid controls, L5 confused names, L7 hid content.)iteration 13
- L8Content-bearing SVG needs a real text equivalent (an sr-only HTML block or role=img + full aria-label); decorative SVG gets aria-hidden. If an agent or screen reader can't read the graphic's words, neither can a judge on assistive tech. (Fourth a11y lesson.)iteration 15
THE HARNESS
AUDIT TRAIL
the complete ledger — all iterations, independent of the replay position above
| # | feat | by | result | lesson | shas | test |
|---|---|---|---|---|---|---|
| 1 | baseline instrument panel (ring + stats + iteration log) | claude | pass | - | bd2aa814 | |
| 2 | interactive ring — click a segment for that iteration's story card | claude | pass | L1 | 209afd81 | |
| 3 | motion tokens + GSAP ring draw-on intro | codex | pass | L2 | 86ccc90d | |
| 4 | flight-recorder replay — scrub and replay the loop's own history | codex | pass | - | 8ba3267b | |
| 5 | learning curve — stacked run bars + cumulative lessons step-line | codex | pass | L3 | 285783c3 | |
| 6 | harness cycle diagram — WRITE→VERIFY→BANK with the fail→LESSON loop | codex | pass-by-evidence at the time; later run flagged passed | L4 | e148ba09 | |
| 7 | checker evidence inside story cards — failure-bundle excerpts | codex | pass | L5 | 215f4e47 | |
| 8 | polish — OG meta, favicon, footer, hook line, mobile pass (5 real bugs fixed) | codex | pass | - | fa60727a | |
| 9 | growth regression — intro scaled with data and hid the ring's controls | claude | shares test 215f4e47 with iteration 7 — this iteration hardened that same ring/story-card feature; latest run passed | L6 | 215f4e47 | |
| 10 | trust audit — hostile agent review turned into committed proof | claude | bank 08c0b17's CI failed on a build error; dfb21f5 fixed it and passed the full SHA-gated suite against the live commit | - | suite | |
| 11 | deep-linkable iterations — ?i=N opens a story card + copy-permalink button | codex | pass | - | 877e0b8b | |
| 12 | failures-only filter — isolate the caught-failure iterations across ring, log, and stats | codex | pass | - | 31d2747b | |
| 13 | keyboard shortcuts overlay + full keyboard nav (the a11y capstone) | codex | failed first (aria-label masked the hint text — L7), fixed in 319e7e0; rerun agent verdict PASS, status blocked per issue #208, failedStepIndex null | L7 | 0447a447 | |
| 14 | the presentation layer — Judge Mode (press J: a self-narrating briefing climaxing in the loop auditing its own checker), the ring's glow, and the hero that states the idea | codex | presentation layer: Judge Mode 186eddc + ring glow 843d0bf + pitch hero 808542f; test passed 21/21 | - | f6c69559 | |
| 15 | the invitation & the trophy — a prominent 'start the briefing' CTA, the shareable Loop Card (download PNG), and Failure Fossils (the exact broken state, preserved) | codex | amplifiers (CTA + Loop Card + Fossils); test caught two a11y regressions (L7 masking in 3817417, L8 SVG-only content fixed in 5f390b1); rerun passed 4/4, run history committed in 1c7c772 | L8 | 1af81937 |
every row: a claim you can check — commit, test, artifact.
LOOP CARD
Ouroboros — the loop that built itself · 15 iterations · 8 lessons · 13 cloud tests · no failure hidden · caught its own checker · upstream: PR #207, PR #213, issue #208 · yazan-o.github.io/ouroboros