---
phase: 04-animation-flow-control
plan: 07
type: execute
wave: 6
depends_on:
  - "04-05"
  - "04-06"
files_modified:
  - .planning/phases/04-animation-flow-control/04-UAT-CEILING.json
autonomous: false
requirements:
  - ANIM-04

must_haves:
  truths:
    - "The large-matrix framebuffer path (7 row-aligned Set64 + CopyFrameBuffer per frame) streams under the same shipped flow control on the real Ceiling Capsule, with the device powered on before any visual run"
    - "The probe-attachment decision (final CopyFrameBuffer, D4-04) is hardware-validated: CopyFB probe acks observed with recorded RTTs compatible with the limit-2/1 s tuning, and the decision + measurements are recorded as phase evidence"
    - "The operator has confirmed visually that the 13×26 stream is smooth AND free of striping/garbled regions (the row-aligned chunking fix validated on the exact hardware the old code would have corrupted)"
    - "Outcomes are recorded exactly as measured; if hardware contradicts the CopyFB attachment (assumption A1), the evidence is flagged for the one-line probe_template_index fallback via gap-closure — never edited ad hoc in this plan"
  artifacts:
    - path: ".planning/phases/04-animation-flow-control/04-UAT-CEILING.json"
      provides: "machine-readable ANIM-04 evidence: per-round loss/delivery, 8-packet frame shape, CopyFB ack RTT median/p95, reported chain dimensions"
  key_links:
    - from: ".planning/phases/04-animation-flow-control/04-UAT-CEILING.json"
      to: "src/lifx/animation/packets.py"
      via: "validates the probe_template_index CopyFrameBuffer attachment (D4-04) on hardware"
      pattern: "uat_ack_stream.py --profile ceiling"
---

**AMENDMENT NOTICE (2026-07-17, applied by 04-10):** The operator-approved
ANIM-03 recalibration (04-GAP-ANALYSIS.md "## Proposed amendment", routed in
04-09-SUMMARY.md) amended the shared gate in uat_ack_stream.py: per-round query
loss ≤ 9.0% plus pooled ≤ 5.0% per run now apply to BOTH profiles, including
this plan's ceiling runs. Task 1's "harness file is byte-identical to its
plan-04-05 commit" criterion is superseded: the harness must instead be
byte-identical to its 04-10 amendment commit. All other criteria (8-packet
frame shape, delivered ≥ 85%, CopyFB ack RTT evidence, ENV-ERROR/FAIL handling)
are unchanged. This plan still executes only after 04-06 Task 2 approval.

**AMENDMENT NOTICE (2026-07-17, applied by 04-11):** The operator routed the
twice-FAILed 04-10 amended absolute gate to a paired-relative redesign
(verbatim reply "2"; approved at the 04-11 checkpoint, verbatim reply "1").
The shared harness (uat_ack_stream.py) now runs the paired-relative gate for
BOTH profiles: ambient-control validity preconditions (ambient loss ≤ 2.5%,
ambient n ≥ 100, every gated round delivered ≥ 0.50), the relative pass rule
(Fisher one-sided p < 0.05 AND blind/gated ≥ 2x, OR gated pooled ≤ 2.5%), a
9.0% pooled gated ceiling, and INCONCLUSIVE (exit 3) as a declared outcome for
ambient-degraded sessions. The 04-10 notice's per-round ≤ 9.0% / pooled ≤ 5.0%
percentages and the delivered ≥ 0.85 pass/fail floor are superseded —
delivered_ratio is now a 0.50 session-validity sanity floor, recorded per
round as evidence. Ceiling-specific criteria are UNCHANGED: 8 packets/frame on
gated rounds, ≥ 1 ack RTT sample per gated round, and the power-on + settle
precondition. Blind-fire rounds on the ceiling stream its full 8-packet frames
unpaced at instrument level. This plan still executes only after 04-06 Task 2
approval.

**SUPERSESSION NOTICE (2026-07-17, applied by 04-12):** The operator retargeted
ANIM-03/ANIM-04 certification to the 04-12 cross-device paired sweep
(04-SWEEP-DESIGN.md, approved at the 04-12 checkpoint). This plan is superseded IN
FULL:

- **Task 1 (headless ceiling measurement) is covered by the Capsule's sweep
  session** in 04-12 Task 4: 13×26 framebuffer path under the paired gate,
  chain-dims-derived packets/frame expectation, CopyFrameBuffer ack RTT evidence,
  A1/A2 dispositions.
- **Task 2 (operator visual checkpoint) is covered by 04-12 Task 5**, the single
  consolidated smoothness + geometry verdict on the Capsule.
- Do not execute any task from this plan.

**FINAL SUPERSESSION NOTICE (2026-07-17, applied by 04-13):** The 04-12
aggregate sweep FAILed (5/5 valid sessions FAIL), so its Task 5 consolidated
visual checkpoint never executed. By operator ruling (verbatim reply "2",
2026-07-17, `04-RULING.md`), ANIM-03/ANIM-04 certification is resolved by
operator acceptance of the cross-device directional dossier, and visual
ownership moves to **04-13 Task 4** — the same Capsule smoothness+geometry
checkpoint 04-12 Task 5 would have run. This plan remains superseded in
full; do not execute any task from it.

<objective>
Execute the ANIM-04 hardware UAT on My Office Ceiling Capsule (192.168.19.231, product
201, 13×26, removed from HA 2026-07-16): power the device on, stream the multi-packet
framebuffer path (7 Set64 + CopyFrameBuffer per frame) under the shipped flow control
for 3 rounds with the concurrent single-shot prober, record CopyFrameBuffer probe ack
RTTs (assumption A1) and the reported chain dimensions (assumption A2), then gate on
the operator's visual verdict — explicitly including "no striping/garbled regions",
the on-hardware proof of the row-aligned chunking fix.

Purpose: ANIM-04 requires the framebuffer path validated on such a device INCLUDING
where the ack probe attaches (Set64 vs CopyFrameBuffer, D4-04) — this run either
confirms the CopyFB decision or produces the evidence for the one-line
probe_template_index fallback.
Output: 04-UAT-CEILING.json evidence + recorded operator verdict + the validated (or
flagged) attachment decision.
</objective>

<execution_context>
@$HOME/.claude/gsd-core/workflows/execute-plan.md
@$HOME/.claude/gsd-core/templates/summary.md
</execution_context>

<context>
@.planning/STATE.md
@.planning/phases/04-animation-flow-control/04-CONTEXT.md
@.planning/phases/04-animation-flow-control/04-RESEARCH.md
@.planning/phases/04-animation-flow-control/uat_ack_stream.py
</context>

<tasks>

<task type="auto">
  <name>Task 1: Run the headless ANIM-04 measurement (3 rounds, Ceiling Capsule, power-on first)</name>
  <files>.planning/phases/04-animation-flow-control/04-UAT-CEILING.json</files>
  <read_first>
    - .planning/phases/04-animation-flow-control/uat_ack_stream.py — the harness contract; the ceiling profile handles set_power(True) + settle before streaming, chain-dimension recording, per-frame 8-packet assertion, and CopyFB ack RTT sampling
    - .planning/phases/04-animation-flow-control/04-RESEARCH.md — Pattern 2 (the D4-04 CopyFB rationale being validated), Assumptions A1 (RTT compatibility with limit-2/1 s tuning) and A2 (chain reports 13-wide; the row-aligned fix is orientation-agnostic either way)
    - .planning/phases/04-animation-flow-control/04-CONTEXT.md — ANIM-04 target block (device details, power-on prerequisite)
  </read_first>
  <action>
    Run the measurement headless and record whatever it actually says:

    1. `uv run python .planning/phases/04-animation-flow-control/uat_ack_stream.py
       --ip 192.168.19.231 --profile ceiling --rounds 3
       --json-out .planning/phases/04-animation-flow-control/04-UAT-CEILING.json`
       — the harness itself powers the device on and verifies reachability first.
    2. Exit 2 (ENV-ERROR): record honestly and STOP — ANIM-04's hardware gate is
       mandatory; surface the blocker (device off-network / powered at the wall)
       rather than fabricating. Exit 1 (FAIL): re-run ONCE for transient rule-out,
       then flag loudly with per-round data. Exit 0 (PASS): proceed.
    3. Record in the summary, against the assumptions they test:
       - A2: the chain dimensions the device actually reported (expected 13×26; if it
         reports 26×13 landscape, the row-aligned math is still correct — note the
         actual packets/frame the harness observed).
       - A1: CopyFB ack RTT median/p95 per round vs the limit-2/1 s tuning (Tiles
         reference: ~98 ms median / ~150 ms p95). Healthy evidence = RTTs well under
         1 s with few expiries and delivered ≥ 85%. If instead expiries dominate or
         delivery collapses below 85% (gate starved because CopyFB acks are too slow
         or absent), the CopyFB attachment is contradicted: record the evidence and
         flag for gap-closure — the fallback is the one-line change of
         MatrixPacketGenerator.probe_template_index's large-tile arm to 0 (first
         Set64), per the D4-04 seam. Do NOT edit src/ in this plan.
    4. Never edit the harness's thresholds, rounds, or pass logic; the harness file
       stays byte-identical to its 04-05 commit.
  </action>
  <verify>
    <automated>test -f .planning/phases/04-animation-flow-control/04-UAT-CEILING.json</automated>
  </verify>
  <acceptance_criteria>
    - 04-UAT-CEILING.json exists with actual per-round data: loss, delivery ratio, 8-packet frame confirmation, CopyFB ack RTT median/p95, expiry counts, reported chain dimensions — never placeholder numbers
    - The A1/A2 assumption outcomes are explicitly recorded (confirmed or contradicted-with-evidence)
    - The harness file is byte-identical to its plan-04-05 commit; no src/ edits in this plan
  </acceptance_criteria>
  <done>The framebuffer path's flow-control behaviour is measured on the real 13×26 Ceiling with the CopyFB attachment decision validated or honestly contradicted — the recorded evidence ROADMAP criterion 4 requires.</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 2: Operator visual verdict — Ceiling 13×26 streaming (ANIM-04)</name>
  <what-built>
    The shipped flow control now paces the multi-packet framebuffer path (7 row-aligned
    Set64 + CopyFrameBuffer swap per frame) on the Ceiling Capsule, with the ack probe
    on the CopyFrameBuffer (D4-04). Task 1 measured loss, delivery and CopyFB ack RTTs
    headlessly. Two things remain human-only: overall smoothness, and confirming the
    row-aligned chunking fix renders CORRECTLY — the pre-fix code would have painted
    shifted, overlapping rows (striping/garbling) on exactly this 13-wide device.
  </what-built>
  <how-to-verify>
    1. Be in your office where you can see the Ceiling Capsule (192.168.19.231). The
       harness powers it on automatically; confirm it is actually lit before judging.
    2. Run a single visual round:
       `uv run python .planning/phases/04-animation-flow-control/uat_ack_stream.py --ip 192.168.19.231 --profile ceiling --rounds 1 --json-out /tmp/04-uat-ceiling-visual.json`
    3. Watch the full ~30 s round and check BOTH criteria:
       a. Geometry: the colour cycle must sweep coherently across the whole 13×26
          panel — no horizontal bands out of place, no repeating/offset stripes, no
          regions stuck on stale colours (any of these means chunking or the buffer
          swap is wrong).
       b. Smoothness: steady ~20 FPS motion; occasional single skipped frames are
          normal (latest-frame-wins), but no multi-second freezes or stutter clusters
          (persistent ~2 frames/s crawling would mean the gate is starving on CopyFB
          acks — the A1 contradiction case).
  </how-to-verify>
  <action>
    Present the how-to-verify steps above to the operator, then BLOCK until the operator
    responds. Record the verbatim verdict in the summary alongside the Task 1 A1/A2
    outcomes. On "approved" the ANIM-04 visual criteria are met; on a described issue,
    do not edit anything — classify it (geometry vs pacing) and capture it as gap
    evidence for `/gsd-plan-phase 4 --gaps`, noting the documented probe_template_index
    fallback if the pacing failure mode matches the A1 contradiction.
  </action>
  <verify>
    <human-check>Operator has watched a full ~30 s streaming round on the powered-on Ceiling Capsule and given explicit verdicts on both geometry (no striping/garbled regions) and smoothness</human-check>
  </verify>
  <done>Explicit operator verdicts on Ceiling rendering geometry and smoothness are recorded verbatim in the summary — approved, or issues classified and captured for gap-closure.</done>
  <resume-signal>Type "approved" if the panel renders coherently and smoothly (ANIM-04 visual criteria met), or describe exactly what you saw (striping/misplaced bands vs freezes/crawling — the two failure modes route to different fixes) — issues go to gap-closure planning</resume-signal>
</task>

</tasks>

## Artifacts this plan produces

| Artifact | Kind | Location |
|----------|------|----------|
| `04-UAT-CEILING.json` — 3-round framebuffer-path evidence incl. CopyFB ack RTTs and chain dimensions | Evidence artefact | `.planning/phases/04-animation-flow-control/04-UAT-CEILING.json` |
| Hardware-validated (or contradicted-with-evidence) D4-04 probe-attachment decision | Decision record | `.planning/phases/04-animation-flow-control/04-07-SUMMARY.md` |
| Operator visual verdict (geometry + smoothness) | Human evidence | `.planning/phases/04-animation-flow-control/04-07-SUMMARY.md` |

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| Harness → LAN Ceiling | Outbound streaming + query load + one power-on command against a user-owned, HA-removed device |

## STRIDE Threat Register

| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|-----------|----------|-----------|----------|-------------|-----------------|
| T-04-12 | DoS (outbound, self-inflicted) | 8-packet frames at 20 FPS (160 pkt/s) ×3 rounds | low | mitigate | Fixed rounds/duration; the shipped gate throttles under congestion; ENV-ERROR guard; device is quiesced (removed from HA) so no competing traffic is disrupted |
| T-04-13 | Elevation/Tampering (unexpected state change) | set_power(True) on a household device | low | accept | Power-on is the documented UAT prerequisite (CONTEXT: animation invisible otherwise); device is the designated test unit |
| T-04-14 | Repudiation | UAT evidence + attachment decision | low | mitigate | Pre-declared thresholds; JSON on disk; A1/A2 outcomes recorded explicitly; harness byte-identical rule |

No packages are installed by this plan (zero-dependency project) — no supply-chain gate applies.
</threat_model>

<verification>
- 04-UAT-CEILING.json on disk with real measured data (or recorded ENV-ERROR)
- A1 (CopyFB RTT compatibility) and A2 (chain dimensions) outcomes explicitly recorded
- Human checkpoint answered explicitly; harness and src/ untouched by this plan
</verification>

<success_criteria>
- ANIM-04 closed: the framebuffer path streams under the same flow control on real 13×26 hardware, the probe-attachment point is decided, hardware-validated and recorded with CopyFB ack RTT evidence, and the operator confirmed coherent, smooth rendering — or the contradiction evidence is flagged for the documented one-line fallback
</success_criteria>

<output>
Create `.planning/phases/04-animation-flow-control/04-07-SUMMARY.md` when done, recording:
the exit code, per-round figures, CopyFB ack RTT median/p95, chain dimensions, the validated
attachment decision, the operator's verbatim verdict, and commit hashes.
</output>
