# REHEARSAL — OpenBell watchtower (Ticket 070 re-filed / mission m-0187)

Frontend Reference Gate rev 2, step 7 handover: what was captured, the gate's pass line, each fault →
its frame → its fix or why it stands, the reviewer's findings → the response, assumptions, what is
unresolved, and **what was not checked**. Written by the mission lead (single-agent re-derivation) on
2026-11-09 against the delivered build.

Deliverable: dark OpenBell watchtower `worker-1/build` → frozen dist `worker-1/build/dist` served by the
read-only launcher `worker-1/serve/server.mjs` on `http://127.0.0.1:4176`, staged at
<https://openbell-staging.pages.dev/> (deployment `a7c02b40`, served bytes byte-identical to the frozen
dist). Frozen dist hashes: index.html `1a4c8cd311d3c2a499b29252922fbd9d84e67c466c84621f77d970bc054da23d`,
JS `assets/index-Cb7s3UYz.js` `c68bc44b6e957608db6b5998a3cd823509bebb5d895edeed05d506532bfd6b0b`,
CSS `assets/index-DDpuraDg.css` `d27f53ae9252b1d5a07e551d3c8a410811ac7ba186610aeef9bcf350d7c43489`
(`work/evidence/frozen-dist.json`).

## Closest reference, and what changed

- **Design source:** the owner-confirmed Ergon design from Nox's 5 Nov face redesign (owner-confirmed
  8 Nov 09:53 ET), transcribed in Ticket 069's THE REFERENCE block — `worker-1/sources/...`/
  `worker-2/reference/REFERENCE.md` sha256 `8f4d3cfcc401579ded80ceeb062dde699e1aa0bff72ed130fa944b5c20b1bb4e`.
  The scheme is the owner's 8 Nov STANDARD CHANGE: dark as a re-skin of that same design (same layouts,
  same componentry, same discipline), never the rejected m-0138/Zara/Midnight-Slate build.
- **Closest real example, captured and copied in:** the m-0170 white OpenBell/front-set build
  (owner-graded "definitely a big improvement") was captured from its running build at 1440×900 and
  390×844 BEFORE this mission's structure existed (`worker-1/references/pre-build/`, manifest with
  sha256 + read markers). Its unlabelled sparkline was deleted and replaced by the real pinned shadcn/ui
  chart, exactly as the amendment orders.
- **What changed after the copy:** rebuilt as a watchtower — one simple view, three lanes, each with its
  own real chart (labelled time x-axis, labelled $/SOL y-axis, gridlines, legend, tooltip with exact
  figures, current value + change readable without interacting); details demoted one level down.

## Captured cases (the pass line counts only frames actually opened)

The build's own mechanical capture pass: **CAPTURE PASS — 12 frames, all expected markers found,
18 chart surfaces, no horizontal overflow, no console errors** (`worker-1/evidence/capture-pass.log`,
regenerated from `worker-1/frames/manifest.json` after the post-review rebuild, capturedAt
2026-11-09T11:28:56Z).

Cases captured: widths 1440×900 desktop and 390×844 phone; views `home` (three lanes watched live),
each lane's detail (`futures`, `kalshi`, `meme`), a hover/tap tooltip with exact figures, and the
labelled DEMO fallback. States seen on the frames: all-live, one lane labelled STALE with its reason,
and DEMO (0/3 with the honest banner). Every one of the 12 frames was opened and read by the lead;
12/12 sha256 match the manifest (`worker-1/frames/read/*.json`, `ALL-READ.json`). Reduced motion was
probed separately and passes (`worker-1/evidence/reduced-motion.json`, re-run against this build).

Faults found in the captures and fixed before freeze (largest first):

| # | Fault (what a viewer sees) | Frame | Disposition |
|---|---|---|---|
| 1 | Demo banner said "No live source answered" even on a partial failure where 2/3 sources were live — a dishonest state label | old `desktop/watchtower.png` (pre-fix frames, kept in `review-070/superseded/`) | **Fixed**: banner now says "N of 3 desk sources did not answer; those lanes show the DEMO snapshot" unless zero answered. New frames `desktop/demo.png`, `phone/demo.png` |
| 2 | No refresh control on the phone face; phone data could only update by reload | old `phone/watchtower.png` | **Fixed**: a real Refresh control in the phone header (visible on every new phone frame) |
| 3 | Refresh was a dead control in demo mode (no request, no change) | n/a (interaction capture) | **Fixed**: Refresh always re-asks the desks and leaves demo if they answer |
| 4 | The visible lane was not in the URL, so reload/Back lost the view | n/a | **Fixed**: lane changes push URL state and a popstate handler restores the view; reload/Back keep it |

Reviewer findings → response (round 2 reviews on the final build are recorded below when they land):

- **GATE 2 fresh-eye (restricted inputs, final frames):** see `review-070/gate2/GATE-REVIEW.md`.
  Round 1 (pre-fix frames) returned PASS with 8 P2 refinements and no blocking finding; it is archived
  as superseded because the frames changed with the fixes. Its surviving refinements are named under
  "Unresolved / carried" below.
- **Polish pass 1 (Ticket 077):** `review-070/polish-ux/POLISH-PASS-1.md` — the numbered refinement list.
- **UX quality review (Ticket 077 §4):** `review-070/polish-ux/UX-REVIEW.md` — its four findings against
  the pre-fix build (F1 dishonest demo banner on partial failure, F2 dead Refresh in demo, F3 no phone
  Refresh, F4 view state not in the URL) are exactly items 1–4 above; the final-build review is the
  record of whether they hold.

## Assumptions

- The owner-confirmed comp PNGs are not on this host; the grammar side-by-side is against the documented
  `REFERENCE.md` and the grammar cards, never a pixel comparison with the comps.
- The public staging deploy is a static bundle; the desk sources are local files/services, so the public
  URL honestly falls back to the labelled DEMO snapshot. The live-data proof is the running build and the
  two VM takes (each VM proved the served bytes equal the delivered dist).
- Sibling mission m-0201 targets the same `openbell-staging` project; our deployment id and served-byte
  hashes are recorded, the canonical URL is re-read at gate time and drift is named, not hidden.
- The two walkthrough takes are sampled/screen recordings of real VMs, bound by VM-side hashes; the
  desktop take's ~2.8 Hz QEMU framebuffer sampling is declared in `worker-2/VIDEO-EVIDENCE.md`.

## Unresolved / carried (not fixed in this delivery)

- GATE 2 round-1 P2 refinements not addressed by the four fixes are carried to the polish list and the
  next ticket: Kalshi chart series label "Paper P&L · base fill" vs the headline "primary arm"; the same
  realisation shown white on the watchtower and amber on the meme detail (one state map wanted); Prop
  detail's LIVE badge can outrank a stale engine warning when the backend says NEEDS YOU; Meme lane has
  a current value but no numeric delta; only lane 1 fully visible above the fixed bottom bar at
  390×844; Kalshi detail table splits identifiers mid-token on the phone; phone tooltip can cover most of
  its plot; duplicate source count in the header and the lane head. These are refinements, none blocking.
- The public staging build cannot reach the local desk sources (see Assumptions) — labelled DEMO there.
- Ticket-077 polish approval is not the builder's to self-issue: the numbered list is handed to Nox with
  the grade handoff and the finish pack states the approval honestly.

## NOT CHECKED (what this handover does not claim)

- Responsive widths between 390 and 1440 (tablet widths) were not captured.
- Reduced motion was probed headless only; the VM takes do not exercise it.
- Keyboard navigation inside the VM takes was not exercised (the Accessibility of the running surface was
  only spot-checked by the UX review record).
- Live-data truth over hours is not claimed: the takes and frames prove the desk sources answering at
  capture time, not that a number is economically correct.
- The phone take's tap-tooltip is shown once (t≈43 s); hover behaviour on real Android hardware was not
  tested.
- The owner-confirmed comp PNGs and any pixel diff against them were not checked (absent from this host).
- The Slack thread rendering of the videos was not verified from a second device; the bundle is a
  phone-playable MP4 over HTTPS.
