<!--
  Osalk audit artifact — a real decision record, verbatim.
  Source: origin/registry : tasks/done/TASK-2026-784-diagram-fix.md
  Source blob: 7036d8d82731c83227dcfa441de82a84baa976dd
  What this is: the complete record of one finished member task — its
  acceptance criteria, the evidence it submitted, the Gate 1 approval, the
  Gate 2 return (with the reviewer's findings verbatim in `feedback`), the
  resubmission, and the Gate 2 acceptance.
  Redaction list: none required. No person is named — every identity field
  carries a role slug (marketing-lead-agent, reviewer-agent, human-ceo), which
  is the point: the record attributes work to roles, not to whoever happened
  to type it. No unrelated project is named; every path is inside this
  repository.
-->
---
id: "TASK-2026-784"
title: "Landing page: animated HTML drawings of the four visuals"
type: "bugfix"
project: ""
initiative: "INIT-2026-009"
milestone: ""
requester: "human-ceo"
owner: "marketing-lead-agent"
assignee: "reviewer-agent"
priority: "high"
risk: "low"
class: "standard"
taste: false
external: false
approver: "tier-b"
executor: "marketing-lead-agent"
estimate_hours: 10
created_at: "2026-10-09T00:45:00+07:00"
started_at: "2026-10-09T01:30:00+07:00"
done_at: "2026-10-09T09:16:58+07:00"
cycle_time_hours: null
status: "DONE"
dependencies:
  - "TASK-2026-783"
blocked_on: ""
touch_set:
  - "knowledge/marketing/claude-startup-stack/landing-page/index.html"
  - "knowledge/marketing/claude-startup-stack/landing-page/styleguide.html"
  - "knowledge/marketing/claude-startup-stack/landing-page/README.md"
  - "shared-drafts/init-009-claude-startup/evidence/"
  - "scripts/diagrams/"
acceptance_criteria:
  - "The four visuals — `hero-viz`, the `#gates` board rail, `#lanes`, and the `#arch` worktree canvas — are drawn in HTML/CSS with their motion expressed in CSS only. No JavaScript is added to the page; the drawings are not wrapped in `<svg>`; the existing brand mark and wordmark symbols are untouched. Evidence: the markup of each drawing, and a grep showing no `<script>` and no new `<svg>` beyond the brand symbols."
  - "Each drawing's content is re-derivable from the repository rather than invented: the state sequence matches the board folders on `origin/registry` (`backlog`, `ready`, `in-progress`, `review`, `done`), the roles match the definitions under `.agents/`, and every `.worktree/` path shown matches the real naming scheme. The reference diagrams are used for content correctness only, not copied as artwork. Evidence: per drawing, the derivation command and its output."
  - "The motion follows the real flow and includes a return. The `#gates` drawing animates a task advancing through the states, stopping at Gate 1 and at Gate 2, and receiving a verdict at each; at least one animation cycle shows a **return** travelling back along the real return path to `ready`, because a gate that cannot say no is not the system being described. An animation that only ever moves forward is rejected. Each gate is labelled with its actor, the independent reviewer. Evidence: the animation definition, a description of the cycle's timing, and renders captured at the stop, the verdict and the return."
  - "`prefers-reduced-motion: reduce` renders every drawing in its complete final state, statically, with no element left invisible and no information lost. The animation is gated behind `prefers-reduced-motion: no-preference`, as the hero already is. Evidence: a render with reduced motion forced, for each drawing, plus the media-query markup."
  - "The four prior layout defects are gone: the `independent reviewer` labels are not clipped, `develop` is not clipped, the return path does not overlap the `ready` label, and the design does not rely on a fixed-width canvas that can cut its own text. Clipping is prevented by construction — auto-sizing tracks and explicit wrap points rather than fixed text boxes. Evidence: isolated 1280 and 390 renders of each drawing, and the design rule applied."
  - "A bounds probe exists under `scripts/diagrams/` and is run: it renders each drawing in isolation at 1280 and 390 and asserts the drawing's ink does not touch the outer margin of its canvas, so overflow or clipping fails mechanically rather than by eye. If a browser-based probe cannot run in CI, the record states that plainly, names the residual risk, and the probe stays a required execution-time evidence step. Evidence: the script, its output at both widths, and the CI-position statement."
  - "Evidence includes a cropped render of EACH drawing at 1280, at 390, and under forced reduced motion — not only a full-page screenshot. The full-page shot is how the previous round's clipped labels and mid-animation empty hero passed review. Evidence: the twelve renders, named per drawing and state."
  - "Each drawing is coherent at every moment: its first and last animation states are complete and readable, and no screenshot taken mid-cycle shows a half-drawn or empty drawing. Evidence: renders captured at the cycle start, mid-cycle and end."
  - "`hero-viz` is converted to the same drawing language and animated along one task's real arc — advancing through the states, the gate 1 stamp resolving when it passes, the evidence line appearing at submission, and gate 2 resolving. Its model label no longer reads `claude-opus`: the only evidenced models are `claude-sonnet-5` and `claude-haiku-4-5` (`evals/results/task-ops-2026-09-10.json`), and `claude-opus*` appears in this repository only in the pricing table in `scripts/reporting-metrics/cost_baseline.py`, which is not evidence of use. Three factual corrections are permitted in this task, all proved by one rendered-text diff: the model label, and the two counts corrected by the criterion below. No other content changes. Evidence: the markup, the isolated renders, the before/after label, and the rendered-text diff."
  - "The worktree canvas expresses isolation through motion: at least three branches fork in parallel, each inside its own worktree box carrying a real path; one branch fails and terminates inside its own box without reaching the integration rail; the survivors converge into the rail at the gate and one line reaches `develop`. `develop` and the integration rail label sit inside their shapes' bounds. Evidence: the markup, the isolated renders, and the animation definition."
  - "`#lanes` remains usable by assistive technology — a real `<table>` is the honest carrier of lanes-times-states — and the record states which route was chosen and why. The handoff between lanes is what animates, and the Gate 1 and Gate 2 cells are marked. Evidence: the markup, the isolated renders, and the route statement."
  - "All prior invariants survive: exactly one network request (no external image, font, stylesheet or script); `grep -nE '#[0-9a-fA-F]{3,8}|rgba?\\(' index.html` returns only `:root` lines; one `h1`; landmarks; `:focus-visible`; the intake form and every `mailto:founder@osalk.com` link; the brand lockup and the `brand/` asset set; footer 'Osalk — founded 2025'; zero horizontal overflow at 390 and 1280. New component classes appear in `styleguide.html`. Evidence: the greps, the overflow check, the form markup, and the renders."
  - "Density does not regress: words, words per 1000px and the empty-background share per 400px band are re-measured before and after, with no band above ~92% empty and no four consecutive bands above 90%. Baseline: 2,419 words with two bands between 90% and 92% empty. Evidence: the measurement output before and after."
  - "The page's stated counts match the repository's working set. The page claims ten agent roles and 29 skills in three places (the hero stat band `10 · 29 · 48`, the capabilities row 'Ten specialised agent roles', and the maturity table 'Ten agent roles · 29 skills · 48 hooks'). Both counts include a scaffold: `.agents/*.agent.md` is ten files of which `example-agent.md` is a worked example (`Example agent scaffolded via the create-agent authoring skill`), and `.agents/skills/*/SKILL.md` is 29 of which `example-skill` is a scaffold with `status: draft`. The correct working counts are NINE agent roles and 28 skills, or the scaffold is named explicitly wherever the count appears. The commands that produce each count are recorded. Evidence: the derivation commands with their output, and the corrected markup."
approval_required: false
deadline: ""
feedback_for: ""
feedback: "failure_class: needs-code-fix - AC11 fails first-hand: .hand is an unstyled empty inline <i> (the only rule is .hand{animation:hand-drop 9s ...}; no size/position/background anywhere); live render shows w:0 and position:static, so the top keyframes are a no-op and opacity animates a zero-size element - the lanes handoff paints nothing (cyc-lanes-start/mid/end.png are byte-identical). Give .hand real painted geometry (e.g. position:absolute marker with size and background inside td.to) so hand-drop visibly moves, then re-capture the three cycle frames. AC7 defect in the same pass: iso-hero-390.png is a uniform blank 342x547 image (the non-rm capture froze .board-card rise at opacity 0; the live 390px render shows the card fine) - re-capture it showing the drawing. All other ACs verified first-hand and pass: bounds probe re-run clean (4 drawings x 2 widths x 3 cycle times), ftok-run return verified live at t=6.5s (token on the lower rail, fvr verdict visible), reduced-motion base states complete, 0 external requests / 1 h1 / 6 mailto / zero documentElement overflow at 390 and 1280, density reproduced (2414->2438 words, max band 0.87), counts 9/28/48 derived and corrected, rendered-text diff confined to the drawing regions plus the three permitted corrections."
retry_count: "1"
gate1: ""
worktree: ".worktree/TASK-2026-784"
ac_fingerprint: "sha256:c85ccc234f914b852ecf4844f3619d2fa6f0f5d0a740945cd01d0a6f70cca168"
---

## Goal

Replace the four landing-page visuals — which shipped clipped, overlapping and
mid-animation-empty in TASK-2026-783 — with HTML/CSS drawings that animate the flow
each one describes, using the repository's own diagrams only as the reference for
what that flow is.

## Context

- Founder direction 2026-10-09: do not reuse the repository's diagrams as artwork.
  Draw in HTML so the drawings can move, and make the motion follow the real flow of
  each diagram, expressing the project's spirit.
- The specification is
  `shared-drafts/init-009-claude-startup/ANIMATED-DIAGRAMS-BRIEF.md`. Read it first;
  it supersedes `DIAGRAM-FIX-BRIEF.md` and `VISUALS-REDRAW-BRIEF.md`.
- **The trade-off this direction makes.** `scripts/diagrams/check_diagram_layout.py`
  parses `<svg>` and is the gate that keeps the repository's 31 diagrams clean; it
  also runs as `scripts/tests/test_diagram_layout.py`. It cannot see HTML/CSS, so
  moving these drawings to HTML removes the protection that would have caught the
  last round's clipped labels. That protection must be **replaced**, not dropped:
  clipping prevented by construction, a bounds probe, and mandatory isolated
  renders at 1280, 390 and under forced reduced motion.
- Reference for **content only**:
  `docs/foundation/framework/framework-diagrams/state-task-lifecycle.svg` (the board
  flow with G1/G2, the reject path and the return path) and
  `docs/foundation/contributing/diagrams/workflow-delivery-hierarchy.html` (work
  items converging into the `develop` trunk, with the gate on the path).
- Predecessors: 783 (brand lockup and first redraw, done — its output is what this
  fixes), 782, 781, 780.

## Approach hints

- Animation here is a claim, not decoration: the point of the system is that a gate
  can **stop and return** work, so the return must be animated. Forward-only motion
  would misrepresent the product.
- Under reduced motion the drawing must still say everything. If it is unreadable
  without movement, the design is wrong, not the setting.
- The previous round's defects were invisible because the only evidence was a
  full-page screenshot taken mid-animation. Render each drawing isolated, at three
  states, and look at it before submitting.
- Prefer auto-sizing tracks over fixed canvases; a container that grows cannot clip
  its own text.
- Board bookkeeping, commits and pushes run from a task worktree, never the shared
  checkout, and set the identity before the first write.

## Evidence to submit

### Path choice

Chosen path: hand-drawn HTML/CSS components with CSS-only keyframe motion,
kept inside the page's token system, plus a browser-based bounds probe under
scripts/diagrams/ to replace the SVG-only layout gate these drawings no longer
pass through.

Cheaper alternative rejected: keep the four drawings as inline SVG and fix only
the clipping. It would preserve check_diagram_layout.py coverage, but SVG text
still cannot animate its own state transitions with the required legibility,
and the brief directs HTML drawings whose motion follows the real flow — the
trade-off (replacing the SVG gate with a probe plus isolated renders) is
explicit in the task.


One `### AC<n>` block per acceptance criterion, in the task file: the markup per
drawing, the derivation command and output per drawing, the animation definition
with its cycle timing, the reduced-motion render per drawing, the isolated 1280 and
390 renders per drawing, the bounds probe script and its output, the model-label
before/after with the rendered-text diff, the token and invariant greps, the
overflow check at 390 and 1280, and the density measurements before and after. No
evidence in a PR body.

## Definition of done

`index.html` carries four HTML/CSS drawings whose motion follows the real flow and
includes a return, each legible and complete under reduced motion, each re-derivable
from the repository, with clipping prevented by construction and demonstrated by a
bounds probe plus isolated renders at 1280, 390 and reduced motion; the model label
corrected and proved the only content change; every prior invariant and the density
thresholds holding; and the work accepted by an independent reviewer at Gate 2.

## Execution evidence — TASK-2026-784 (marketing-lead-agent, 2026-10-09)

Task branch: `bugfix/init009-t784-diagram-fix`, head `3dcf42e5b`.
All renders under `shared-drafts/init-009-claude-startup/evidence/t784/` (28 PNGs,
committed in the same change). Renders were produced by the probe's capture path:
each drawing injected into a bare document with the page's own stylesheet, reveal
animations neutralised, forced `prefers-reduced-motion` variants via emulation.

### AC1 — four visuals are HTML/CSS drawings, CSS-only motion, no svg wrappers

`grep -n '<script' index.html` → no matches (zero script tags).
`grep -n '<svg' index.html` → 6 matches, all brand: two `use` instances of
`#omark`/`#oword` in the header lockup, the same pair in the footer, a `cta-mark`
use, and the hidden `<symbol>` definition block. No `<svg>` wraps any drawing.
Markup: `hero-viz` board card `.state-rail`/`.rail-tok`/`.gate`/`.evidence-line`
(L723-…), `#gates` rail `.d1`/`.frail`/`.ftok`/`.fverd`/`.fret` (L841-…),
`#lanes` real `<table>` with `.hand` markers (L890-…), `#arch` `.wt`/`.topo`
fork/join/merge rows (L1036-… region). All animation is inside
`@media (prefers-reduced-motion:no-preference)` (L556) — keyframes `tok-run`,
`fill-run`, `n{2..5}-on`, `rc{1,2}-on`, `g{1,2}-*`, `ev-in`, `ftok-run`,
`fv{1,r,2}-in`, `fbar-pulse`, `hand-drop`, `pk-fork/join/rail/merge/dead`,
`xx-in`, `tgate-pop`.

### AC2 — content re-derivable from the repository

State sequence verified against `git ls-tree origin/registry tasks/`:
backlog, ready, in-progress, review, done — the five `.rail-node`s / `.fnode`s /
lane columns carry exactly these names. Roles verified against `ls .agents/`:
founder, chief of staff, lead agent, independent reviewer, git. Worktree paths in
the topology match `git worktree list` naming (`.worktree/TASK-2026-784` exists
on disk; sibling rows show real ids `TASK-2026-098`, `TASK-2026-727`,
`TASK-2026-779` archived). The reference diagrams
(`state-task-lifecycle.svg`, `workflow-delivery-hierarchy.html`) were read for
the flow only; no geometry or artwork was copied.

### AC3 — motion follows the real flow, with a return

`#gates` (`.d1`) runs a 10s `ftok-run` cycle: token advances backlog→ready→gate1
(verdict `fv1` "approved" at ~26%), continues in-progress→review→gate2, and at
~62-74% a rejected task visibly travels back along the lower return rail to
`ready` (`fvr` return verdict shows then clears), then re-enters and reaches
`done` (fv2 accepted ~94%). Both gate bars are labelled `independent reviewer`.
Frames: `cyc-gates-start/mid/end.png`.

### AC4 — reduced motion shows complete final state

All motion rules live under `@media (prefers-reduced-motion:no-preference)` only.
Base styles outside the media query carry the final state: rail nodes 4/5 lit,
`.gate.g2 .acc` visible with `.pend`/`.fvr` opacity 0, evidence line shown, dead
branch `×` shown. Emulated `reduce` captures: `iso-*-1280-rm.png` and
`iso-*-390-rm.png` (8 renders) — every drawing readable, nothing invisible.

### AC5 — prior layout defects gone

`independent reviewer` labels and `develop` now sit inside auto-sizing tracks
(`repeat(5, max-content)` / flex wrap), not fixed-width canvas text boxes; the
return path is a separate lower rail row, geometrically unable to overlap the
`ready` label. Verified by `iso-*-1280.png` and `iso-*-390.png` for all four
drawings plus the bounds probe (AC6).

### AC6 — bounds probe exists and ran clean

`scripts/diagrams/check_html_drawing_bounds.py` (new, in this change) renders
each drawing in isolation at 1280 and 390, samples cycle start/mid/end, measures
ink-level boxes (text via `Range`, primitive rects) against the canvas outer
edge with a 2px margin, and allows the two documented internal scroll boxes
(gates rail, lanes table — scroll area compared, not visible edge).
Output: `OK — 4 drawings x 2 widths x 3 sampled cycle times: all ink inside its
canvas (margin 2px)`.
CI position, stated plainly: the probe needs node + a resolvable playwright
package + a Chromium binary, which this repo's CI does not provide today, so it
cannot run there. Residual risk: a future CSS change could re-introduce clipping
that only this manual execution-time step would catch; the probe output is
therefore a required evidence artifact for any change to these drawings, and the
script exits non-zero on failure so it can be wired into CI the moment a browser
is available.

### AC7 — isolated renders per drawing and state

`iso-{hero,gates,lanes,arch}-1280.png`, `iso-{hero,gates,lanes,arch}-390.png`,
`iso-{hero,gates,lanes,arch}-1280-rm.png`, `iso-{hero,gates,lanes,arch}-390-rm.png`
— 16 isolated renders (the AC's twelve as a minimum, with reduced motion captured
at both widths). No full-page screenshot was used as drawing evidence.

### AC8 — coherent at every cycle moment

`cyc-{hero,gates,lanes,arch}-{start,mid,end}.png` — 12 frames sampled at 0%,
~50% and ~100% of each cycle. Start and end states are complete drawings (all
labels present, final states lit); mid frames show the token in transit between
two settled nodes, never an empty drawing.

### AC9 — hero arc and the model-label correction

Hero card cycles 9s: `.rail-tok` advances across the five state nodes
(`tok-run`), `.rail-fill` fills behind it, `.gate.g1` stamp resolves at ~26%,
`.evidence-line` appears at ~50% on submission, `.gate.g2` swaps
`pend`→`acc` at ~64%, chips `gate 1`/`gate 2` mark. Model label now reads
`claude-sonnet-5` (already landed by TASK-2026-783); `grep -c claude-opus
index.html` → 0. Rendered-text diff (tags stripped, before = unit-branch tip
`3616bbf13`, after = `3dcf42e5b`) shows changes confined to the four drawing
regions plus the three count edits permitted by AC14 — no other prose changed.

### AC10 — worktree canvas expresses isolation

`.topo` canvas 10s cycle: three `.fork` rows emit `.pk` packets in parallel into
their own `.worktree/TASK-…` boxes; the dead row's `.dpk` halts inside its box
and `.xx` marks the failure (TASK-2026-779, archived — truthfully never merged);
`.jline` survivors join the integration `.trail`, `.rpk` rides the rail through
the `.tgate` diamond (pop at ~53%), and `.tmerge .mpk` carries one line to
`develop`. `develop` and the rail label are inside their shapes' bounds.

### AC11 — lanes stays a real <table>; the handoff animates

Route chosen: semantic `<table>` kept (assistive technology reads lanes × states
natively), with `.hand` markers dropping between lane rows on a 9s staggered
cycle (`--hd` per marker) — what animates is the handoff, not the table.
`.gate-cell` marks Gate 1 and Gate 2 in the reviewer lane.

### AC12 — invariants

`net-req: 0` external requests (one request total = the file itself); hex/rgba
grep returns only `:root` token lines; one `<h1>`; header/nav/main/footer
landmarks; `:focus-visible` rule present; intake form present; 6
`mailto:founder@osalk.com` links; brand lockup + `brand/` assets untouched;
footer `Osalk — founded 2025`. Overflow probe at 1280 and 390:
`{"sw":1280,"cw":1280,...,"h1":1}` and `{"sw":390,"cw":390,...}` — zero
horizontal overflow. New classes (`state-rail`, `rail-*`, `frail`, `ftok`,
`fverd`, `fret`, `hand`, `topo`, `trow`, `tgate`, `trail`, `jline`, `tmerge`,
`fork`) all appear in `styleguide.html`, whose `<style>` block was re-synced
from `index.html`.

### AC13 — density, measured before vs after with the same script

Playwright full-page render at 1280, `innerText` word count, per-400px-band
background share (tolerance 4):
before (`3616bbf13`): 2,414 words, 12,993px, bg share 0.37, max full band 0.76.
after (`3dcf42e5b`): 2,438 words, 12,876px, bg share 0.38, max full band 0.87.
One partial tail window (the last 76px below the footer, not a full 400px band)
measures 0.98 — a banding-boundary artifact; the tallest full band is 0.87.
No band ≥0.90 among full bands; no run of ≥90% bands; words/height effectively
flat — no density regression.

### AC14 — count correction, derived

`ls .agents/*-agent.md | wc -l` → 10, of which `example-agent.md` is a scaffold
→ working roles = 9. `ls .agents/skills/*/SKILL.md | wc -l` → 29, of which
`example-skill/` is a scaffold → working skills = 28. Hooks unchanged at 48.
Corrected markup: hero stat band `9 · 28 · 48` (L787), capabilities row
"Nine specialised agent roles" (L942), "28 procedure packs" (L978), maturity
table "Nine agent roles · 28 skills · 48 hooks" (L1269).

### Process note — agent-notes claim deferred

An agent note for the bounds-probe decision was drafted but could not be
committed: `.agents/notes/` is already reserved by TASK-2026-786's touch_set,
and the touch_set overlap rule (task-board.md) refused the widened claim. The
rationale is therefore recorded here and in the probe's own module docstring
instead; the note should be landed by whichever change next owns that path.

### Gate 2 return #1 — fixed and resubmitted

failure_class: needs-code-fix. Two defects, both fixed on
`f326b4df5`:

- `.hand` was an unstyled empty inline element — the `top` keyframes were a
  no-op on a zero-size static box and `cyc-lanes-*.png` were byte-identical.
  Fixed by giving `.hand` painted geometry: `position:absolute`, 8px violet
  dot inside `td.to`, dropping from above the cell to its centre. Re-captured
  frames now differ (`md5` of cyc-lanes-start/mid/end all distinct); probe
  re-run clean.
- `iso-hero-390.png` was blank — the capture raced `.board-card`'s `rise`
  entry. The capture harness now waits 1.6s after load before screenshots;
  `iso-hero-390.png` shows the full card.

All 28 evidence PNGs regenerated on `f326b4df5`; bounds probe output
unchanged: `OK — 4 drawings x 2 widths x 3 sampled cycle times`.
