The actual documents the agents read and work from, shown exactly as they are on disk — not a summary. See the progress view instead · All projects
# PLAN-SKIPPY-FINISH.md — finish the Skippy app and its voice app, to Deep Mint · Linen, and call the four channels done
**🔴🔴 THIS IS THE ONLY PLANNING DOCUMENT FOR THE SKIPPY-FINISH DRIVE. Do not create a second plan, tracker, summary, or scratch state file for it — extend THIS file or its STATE-SKIPPY-FINISH.md companion, and log a dated delta in PLAN-CHANGES-SKIPPY-FINISH.md. Any status view about this drive is GENERATED from this plan; if a view disagrees, the plan wins.**
**Precedence (Nick, 2026-09-04, verbatim: "The only thing I want to do is finish the hub and finish Skippy in the voice app. That's all I care about." and "finish skippy then we do gracie and neeko later / finish voice app then we deploy the same etup in the hub and family app"):** this plan is the execution authority for finishing the Skippy app. The prior programme index (PLAN-SMP-PROGRAMME.md, same folder) and the per-lane files PLAN-SMP-1.md, PLAN-SMP-4.md, PLAN-SMP-6.md, PLAN-SMP-7.md, PLAN-SMP-10.md remain as the historical record and evidence store — their 15-step integration machinery is not executed further for this scope. Marking them SUPERSEDED in their own headers is a coordinator edit, flagged in this plan's handback, not silently done here (three peer plans landed the same night; one hand places the markers).
**Owner:** the Skippy-finish drive session · **Overseer:** one Fable overseer in ONE thread (Nick, 2026-09-04: "the new plans will deploy fable agents as overseers for build work and deisng QA") · **Design authority:** Sienna (`creative-director`), UI only — Nick's explicit call in the 2026-09-03 UI handoff.
**Rule: no step begins until its named entry condition is proven. A step whose named dependencies are satisfied MAY start, whatever its number.**
---
**NORTH STAR:** Nick opens Skippy on his Mac and talks back and forth with it, hands-free, no buttons — and everything he sees wears the Deep Mint · Linen design he approved, exactly. Slack, Gmail, WhatsApp and Alexa are each tested, confirmed working, and called DONE. The whole setup is written down so the Hub and the family app can wear the same one next. (His words, 2026-09-04: "i just want to finish the skippy app"; 2026-08-28: "we chat back and forth without clicking buttons"; 2026-09-03: "the UI that shows everywhere for this app to look like deep mint and linen period no exceptions".)
**FINISH LINE — written once, at planning time; the bar never rises mid-drive. When each item passes its one check, this drive is DONE and everyone stops. Anything found after that goes on the NEXT list and is not worked.**
1. A real spoken back-and-forth conversation with Skippy completes on his Mac through the OpenAI voice path, with the voice switches ON for his real use, and the transcription-only invariant intact.
2. Every Skippy surface (S1 Talk, S2 Dispatch, S3 Status, S4 Thread, S5 mic widget, S6 collapsed window, and the Signal shell if STEP 1 proves it user-facing) samples `#ABCFAC` and `#F0E8DA` at the spec's named points, greps zero for the forbidden list, and passes Sienna's six checks including the dark-forced-to-light pixel comparison.
3. The installed desktop app launches, converses, and shows honest offline/error/recovered states, proven by behavior on the installed app — never by hashing its launcher.
4. Slack, Gmail, WhatsApp and Alexa each pass their testing phase — existing harnesses green, re-run first-hand, plus one live round-trip each (or an honest NOT AGENT-TESTABLE with the single consolidated human ask stated) — and each is recorded DONE and listed as an optional test layer for the rest of Skippy testing.
5. The reuse kit exists and a cold reader used it, dry-run, against a second surface without asking a question.
6. A blind final QA re-ran all 18 manifest rows and 18/18 PASSED (an execution count is not a pass count; a shortfall is reported to Nick as NOT DONE and only he can accept it); its verdict is recorded unchanged; the postmortem is written into this plan.
---
> **STEP 0 — ARM THE LOOP, BEFORE ANYTHING ELSE.** Set a 5-minute loop. Every time it fires,
> answer these four in order and CORRECT any failure before doing anything else:
> 1. **NORTH STAR** — is what I am doing this minute moving this plan's North Star? If not,
> drop it and take the highest-value unblocked step that does.
> 2. **FAN-OUT** — is my queue full up to the concurrency cap (§T)? Full capacity means the
> cap is reached and a queue of ready work sits behind it — NEVER "launch everything at
> once". Below the cap with ready work → dispatch now. At the cap → queue, don't launch.
> 3. **CHEAP** — are cheap models doing the building? If anything expensive is building,
> move that work down now.
> 4. **BLOCKED** — for anything I have called blocked: name the three concrete things I tried.
> If I cannot, it is not blocked — drive through it now.
> Then keep building. The loop never stops until the FINISH LINE is proven.
---
## Already true (the distilled past — facts, not story; live items re-measured 2026-09-04)
- The approved look is Deep Mint · Linen; the mockup is the Deep Mint card in `projects/personal/skippy-app/design-directions/voice-options.html`, the full written spec (tokens, type, geometry, contrast corrections, the six proof checks) is `projects/personal/skippy-app/design-directions/DEEP-MINT-LINEN-SPEC-2026-09-03.md`, and a full-shell render exists at `projects/personal/skippy-app/design-directions/deep-mint-linen-full-shell-20260903.html`. Nick confirmed dark mode LOCK TO LIGHT ALWAYS (2026-09-03) and ruled Deep Mint the visual authority for ALL Skippy surfaces (spec Part 7).
- The voice migration to OpenAI is a resolved architecture with real code: `projects/personal/skippy-app/skippy-code/lib/openai-realtime-adapter.mjs` exists; the SPEAKING half is independently verified (`projects/ops/skippy-master-plan/evidence/smp-1-07-adapter-independent-verify-claude-2-0-f3.md`); the LISTENING half WAS independently verified on 2026-09-03 (`projects/ops/skippy-master-plan/evidence/smp-1-07-listening-independent-verify-claude-2-0-c0.md` — found by this plan's own cold reader after a first draft called it self-checked-only off the stale handoff) and that verification found a real defect (`close()` deadlocking a pending `next()`, measured TIMEOUT at 500ms), a builder fix whose RE-VERIFICATION never completed, and a warning that `startOpenAIListeningSession` is NOT the code path that ships — the browser-side connection is; the server/browser wiring landed 2026-09-03 with both feature flags defaulting OFF (`projects/ops/skippy-master-plan/evidence/smp-1-07-wiring-local-proof.md`; commits recorded there live in skippy-code's OWN nested git repo — `cd` into it before any git command). The Shape 2 invariant: OpenAI never generates reply content — transcription-only sessions, proven live 2026-09-01.
- Real hardware audio has been exercised: `projects/ops/skippy-master-plan/evidence/smp-1-07-real-hardware-audio-test.md` and `projects/ops/skippy-master-plan/evidence/smp-1-07-interruption-and-failure-real-tests.md` exist and record real runs.
- The Skippy Mac server is RUNNING now — `pgrep -fl "skippy-app/server.js"` returned pid 996, measured 2026-09-04. `Skippy.app` is installed in /Applications (plus ~15 versioned backups); no desktop shell process was running at measurement time.
- The desktop shell's live target is `https://family.heroesandsidekicks.io/?frame=window` (per `projects/personal/skippy-app/desktop/main.js` lines 7/136/141; skippy-cloud.fly.dev is retired as a surface). The live URL answered `200 text/html` on 2026-09-04.
- The Skippy frame surfaces S1–S4 are controlled by `projects/personal/family-app/css/signal-frame-window.css`; S5 is `projects/personal/skippy-app/desktop/widget.html`; S6 is `projects/personal/skippy-app/desktop/collapsed.html`.
- 🔴 **THE RESKIN IS ALREADY PARTLY LANDED ON DISK — measured 2026-09-04, twice (author + cold reader), so the reskin steps VERIFY AND CLOSE GAPS rather than paint from zero.** Present already: `#ABCFAC`/`#F0E8DA` tokens in signal-frame-window.css (5 hits), `color-scheme: light` + accent tokens in widget.html:36 and collapsed.html:37, zero `prefers-color-scheme` in all three, and the plan's short forbidden list greps 0 in the frame CSS today. Still real, verified work: the mono `!important` block (count 1 in the frame CSS), the DARK HEXES still live in `projects/personal/skippy-app/desktop/main.js` (2 hits — line 89 returns `#07080a` when macOS is dark, so the native window ground still goes dark) and 1 hit in `skippy-code/public/index.html`, the shell itself (`#ABCFAC` count 0 — the least-painted surface), the font (see next bullet), and spec-conformance of geometry/type that no grep has checked. The spec's own line numbers are stale; every reskin step re-measures before editing.
- The only Neue Montreal asset on disk is `projects/personal/skippy-app/design-directions/fonts/NeueMontreal-Medium.woff` — ONE weight, one format, outside the family-app served tree (cold reader, 2026-09-04). The spec's type scale needs weights 400 and 700; the brand website carries a copy per the spec. Loading the font is therefore real work including new font asset files, and the fence allows exactly that.
- All nine mockup colours already exist in `projects/personal/family-app/css/tokens.css` under other names (spec Part 1 table), and a proven re-pointing technique exists in the codebase (the "Tulum Natural" skin, `family-app-field-preview/css/field.css` per the spec) — the reskin re-points tokens, it never renames an element id or class — renaming one breaks voice silently. The shell's id COUNT is disputed between its two sources (the spec says 26; the later, same-day handoff says 27 after a re-grep), so no step asserts a number: the contract is a MEASURED LIST — capture the sorted unique id set before the edit, diff after, empty diff or the step fails.
- The four channels are BUILT, and their harnesses pass bare, re-run first-hand 2026-09-04, exit 0 each: Slack/Gmail — `projects/personal/skippy-app/channels/_test-smp6-secure-boundary.mjs` ("SMP-6 STEP 2 PASS"), `_test-smp6-gmail-draft-only.mjs`, `_test-smp6-provider-failure-recovery.mjs`; WhatsApp — `projects/personal/skippy-app/wa/_test-smp7-secure-boundary.mjs` ("SMP-7 STEP 2 PASS", 10 checks); Alexa — `projects/personal/skippy-app/alexa/test-adapter.mjs` ("SMP10 ADAPTER PASS requests=6 responses=6") and `test-schema.mjs`, with six more test files, a simulator, and device discovery in the same folder (real code dated 2026-09-01–03, previously mis-recorded as 0% in its own lane plan).
- The old lane plans are stale against the product in both directions (measured: PLAN-SMP-1.md's STEPS read 0% with its named harness absent while the evidence folder holds real verified voice work; PLAN-SMP-10.md read 0% over a built adapter). No old plan's claim is inherited here as fact — this plan cites disk and live measurements only, and STEP 1 re-pins the live baseline.
- ZION-8 is done 100% per Nick and serves as the security approval gate (`projects/ops/zion/PLAN-ZION-8-approval-system-update.md`) — security work in this drive is click-gated through it and sits in the anti-scope.
- The outside cheap vendors were down at planning time (one over weekly limit, one at zero balance) — builders fall back per the routing rules at dispatch time; the plan still names the cheap tier as default.
## 0 · Gate Zero receipts (the plan may not exist without these)
- Failure Mode Registry loaded: 2026-09-04, 167 entries per the checker's own count (the gate is authoritative over a hand count); all covered in §4.
- Canonical specs loaded: `.claude/skills/plan/SKILL.md` (incl. §W and §Z, added 2026-09-04), `projects/ops/PROMPT-SPEC.md` §6, `projects/ops/agents/CODE-STANDARD.md`, `projects/ops/agents/CREATIVE-QA-STANDARD.md`, `projects/personal/skippy-app/design-directions/DEEP-MINT-LINEN-SPEC-2026-09-03.md`, `projects/ops/REGROUP-SOURCE-2026-09-04.md`, `projects/ops/skippy-master-plan/HANDOFF-PROMPT-SMP-1-voice-v3.md`.
- Ownership check: the SMP programme index and lane plans govern this ground today; this plan extends that estate as its finishing authority rather than building beside it — precedence stated in the header, supersession markers routed to the coordinator. No second Skippy-finish plan exists (searched this folder and ACTIVE-WORK by name, 2026-09-04).
- Expected inputs confirmed to exist: every file named in this plan's proofs was opened or globbed on disk 2026-09-04 (mockup, spec, frame CSS, tokens, widget/collapsed, desktop harness, skippy-code server/voice/adapter files, all channel and Alexa test files, evidence folder); the live surface answered 200; the Mac server process was found running.
- Model cache / matrix: executor names below come from `projects/ops/walkaway/MODEL-MATRIX.md` vocabulary (glm builds · sonnet checks · fable oversees and design-QAs).
- PLAN AUTHOR: Boris 1 of 3 (senior-engineer, Fable), 2026-09-04, on Nick's direct dispatch.
- COLD READER: a fresh adversarial reader (spec-breaker, 2026-09-04), given only Nick's scope words and the plan, verdict NOT READY with seven ranked disputes — five verified against the real files (reskin already partly landed so three proofs couldn't fail; forbidden list five tokens short with the dark hexes fenced off in main.js; id count 26-vs-27 unreproducible; listening-half claim stale against the 2026-09-03 c0 verification; font undeliverable inside the fence) plus two structural (720px-cap owner; STEP 16 command/blindness/100%-ambiguity). ALL SEVEN corrected in place the same day — every affected proof now fails on today's file. The coordinator still owes the cross-plan duplicate-ownership pass across all three Boris plans.
- PROMPT-SPEC scan (P1–P7): P1 "finish"/"done" defined by the FINISH LINE above in his words; P3 "slack gmail whatsapp etc are pretty much done right?" was verified on disk and live rather than accepted (they are built and their harnesses pass); P4 "everywhere" bounded by the six named surfaces + Signal shell; P7 his 2026-09-04 multi-part message split item by item in §1a and the sheet. Remaining V1 ambiguities are the sheet rows in §1a.
## 1 · Goal and definition of done
**What we're building, one paragraph.** Finish — not rebuild — the Skippy app: turn the already-wired OpenAI voice path ON and prove a real hands-free conversation on Nick's Mac; dress every Skippy surface in Deep Mint · Linen exactly per Sienna's spec; prove the installed desktop app honest in its failure states; run the four channel adapters through a testing phase and call them done; and write the reuse kit so the Hub and family app deploy the same setup next.
- **HOW IT'S USED:** Nick (and Chantelle, equal privileges per the 2026-08-20 parity ruling) opens the Skippy desktop app or the family app's Skippy tabs and talks back and forth, hands-free; replies come back spoken and on screen. · HOW WE KNOW: Nick, 2026-08-19 "we use the family app, the hub, the desktop app - thats all"; 2026-08-28 "we chat back and forth without clicking buttons"; parity ruling 2026-08-20.
- **WHAT IT LOOKS LIKE:** Deep Mint · Linen, pixel-exact to the mockup: Paper ground, Ink text, one mint accent `#ABCFAC`, Linen bubbles `#F0E8DA`, all sans, light always. · HOW WE KNOW: the mockup + spec cited in Already true; Nick 2026-09-03 "deep mint and linen period no exceptions" and dark-lock confirmation.
- **WHERE IT LIVES:** the installed `Skippy.app` on Nick's Mac (loading `https://family.heroesandsidekicks.io/?frame=window`), the family app's Skippy tabs on his phone, and the channel adapters inside Slack, Gmail, WhatsApp and Alexa — Nick opens all of them. · HOW WE KNOW: desktop/main.js:141 read directly; live URL answered 200 on 2026-09-04; Nick's 2026-08-19 surface ruling.
- **WHAT IT MUST DO:** (1) complete a real spoken back-and-forth via the OpenAI path with the transcription-only invariant intact; (2) render every Skippy surface in Deep Mint · Linen passing Sienna's six checks; (3) launch and behave honestly offline/on-error as an installed app; (4) pass a testing phase for each of Slack, Gmail, WhatsApp, Alexa and record each DONE and available as a test layer; (5) ship a reuse kit a cold reader can apply. Each becomes an eval in §6.
- **NOT in scope:** the ANTI-SCOPE —
- **Security work of any kind** — audits, key-chasing, hardening, "while I'm here" fixes. Click-gated through ZION-8; the dedicated security pass is its own phase AFTER this finish line, on Nick's click. Seeing something security-shaped costs one line on the NEXT list. (Nick, 2026-09-04: "we do not do security audits until the end period nobody aiuthorized that.")
- **The Hub and the family app's non-Skippy screens** (Home, Calendar, To-Do, Shopping, Finances, Health — Pop-Bento look) — the Hub is a peer plan's ground; the family screens get the Deep Mint setup LATER via the reuse kit, per "then we deploy the same etup in the hub and family app".
- **Gracie and Neeko** — "finish skippy then we do gracie and neeko later" (Nick, 2026-09-04).
- **`skippy-app/standalone/`** — half-built, third look, wired to nothing; out per Sienna's recommendation (sheet row 7).
- **Rebuilding any channel adapter** — all four are built; they get a testing phase, not construction (Nick, 2026-09-04, and verified on disk).
- **skippy-cloud.fly.dev as a proof surface** — retired per desktop/main.js:7,136.
- **New scheduled jobs** — "there are no scehdueld jobs right now because everything is fucked" (Nick, 2026-09-04); nothing here creates one.
- **REPLACING / RETIRING (keep alive, do not invest):** the ElevenLabs voice path stays as ROLLBACK only — it is not removed and not improved; the talk-panel dictation flow is replaced by the continuous voice loop — no further investment; the old grey-and-amber desktop look is replaced by Deep Mint; the SMP programme's 15-step integration machinery is not executed further for this scope.
- **Trip-over protocol:** a lane that finds something outside the fence writes ONE dated handover line to its named owner (Hub findings → the Hub plan's owner; family-app non-Skippy findings → SMP-2's record; security-shaped findings → this plan's NEXT list), then back to building — never investigates, never fixes.
Any load-bearing inherited fact above carries its re-measure command in §6 or in its own step's proof. A fact nobody measured is not carried here.
## 1a · Critical variables — the confirmation sheet is GENERATED from this table
| # | The variable, in plain words | Value chosen | Alternatives rejected | Class | HOW WE KNOW | Cost if wrong | CONFIRMED |
|---|---|---|---|---|---|---|---|
| 1 | **SURFACE — where this lands and who opens it**: the installed Skippy desktop app + the family app's Skippy tabs, opened by Nick (Chantelle equal) | Desktop app + family-app Skippy tabs | skippy-cloud.fly.dev (retired); standalone/ (unwired) | V1 | Nick's own dated words | Building for a screen he never opens — the exact 2026-08-19 failure | Nick, 2026-08-19, "we use the family app, the hub, the desktop app - thats all"; re-affirmed 2026-09-04 "finish the skippy app" |
| 2 | The visual authority for every Skippy surface | Deep Mint · Linen, light always, per Sienna's 2026-09-03 spec | Signal grey/amber as a look; any dark variant | V1 | His verbatim ruling plus the dark-lock answer | Pixel-perfect against the wrong reference | Nick, 2026-09-03, "deep mint and linen period no exceptions" + LOCK TO LIGHT ALWAYS |
| 3 | The font that actually loads | Neue Montreal (real webfont, Inter properly loaded as fallback) | Inter only; silent system fallback (today's state) | V1 | Sienna's spec §Part 1(b) marks it OPEN with a recommended default | Every size/weight in the spec renders off | DEFAULTED per Sienna's 2026-09-03 recommended default; sheet row for override — build proceeds, only a font swap rides on the answer |
| 4 | The S5/S6 derived designs (mic widget + collapsed window, no mockup of their own) | Sienna's derivation from the mockup's own mic button (spec Part 5), shown to him live 2026-09-03 | Inventing a new design; leaving them grey | V1 | Spec Part 5 records shown-live, final verdict not yet given | Two desktop surfaces wearing a look he didn't pick | DEFAULTED per Sienna's derivation, 2026-09-03; sheet row for his final verdict — Sienna's own QA gates it either way |
| 5 | What "done" means for the four channels | Harnesses green re-run first-hand + one live round-trip each, then DONE, then listed as optional test layers | Full re-verification programmes; rebuilding them | V1 | His words define the bar | Either endless re-testing or a false done | Nick, 2026-09-04, "slack gmail whatsapp alexa get a testing phase to confirm they work and are ready for primetimes then called done" |
| 6 | When the voice switches flip ON for his real use | Immediately after the end-to-end real-mic test passes (STEP 4), ElevenLabs kept as rollback | Waiting for a separate show-and-tell round first | V1 | Deploys are not an approval class; finishing is the whole order | He keeps using the old path while the new one sits done | DEFAULTED to flip-on-pass, 2026-09-04, from "finish the voice app... and be done"; sheet row so he can choose show-me-first instead |
| 7 | Whether `skippy-app/standalone/` is in scope | OUT | Restyling it too | V1 | Sienna's spec marks it OPEN with a recommendation | Wasted work on an unwired app | DEFAULTED OUT per Sienna's 2026-09-03 recommendation; sheet row |
- V1 confirmation reads `<name>, <date>, "<their own words>"` — DEFAULTED rows carry the named default's author and date and appear on the sheet; work downstream of an overridable default is a swap, never a rebuild.
- V2 confirmation reads `opened <what>, <date>, saw: <what was actually there>` — all V2 facts in this plan carry that form in Already true.
**Considered and ruled NOT critical** *(the denominator — never demote a variable silently)*:
- The two contrast corrections and the fault colours (spec §4.2/§4.3) — accessibility floors measured against the app's own palette; Sienna's authority as design owner covers them, and overruling is a one-line token change.
- Which cheap vendor builds — routing-rule territory, not a build fork.
- Alexa live-device availability — handled inside STEP 14 as an honest evidence state, not a plan fork.
## 1b · Subproject decomposition — could a piece of this ship on its own?
- **SINGLE SUBPROJECT:** everything here finishes ONE product — the Skippy app Nick opens. The channels are testing phases of that same app (his own words fold them into "the rest of the ksippy testing as layers"), the reskin and the voice finish land on the same three surfaces, and none of it would be signed off or used alone. The Hub and family-app deployments of this setup are OTHER plans' work, reached through the reuse kit, and are named in the anti-scope with owners.
## 2 · The complete UX map (this becomes the test manifest verbatim)
| Id | Screen / entry point | State (default·empty·error·loading) | Element / interaction | Expected behavior | Navigation from → to |
|---|---|---|---|---|---|
| U1 | S1 Talk (frame window) | default | speak; reply renders + speaks | Deep Mint tokens exact; assistant prose on Paper, user bubble Linen | dock mic → conversation |
| U2 | S1 Talk | listening/thinking | mic states | accent states per spec Part 5 vocabulary; no colour-only status | conversation |
| U3 | S1 Talk | error (provider down) | spoken turn fails | honest fault state in Fault ink `#a05f42`, text label present | conversation → error |
| U4 | S2 Dispatch | default·empty | handback list rows | list-row geometry per spec §3.5; pip never meaning-alone | tab → list |
| U5 | S3 Status | default·empty | live-work rows | same row grammar; no amber anywhere | tab → list |
| U6 | S4 Thread | default·loading | opened conversation | type scale per spec §3.4 | list row → thread |
| U7 | S5 mic widget | resting·listening·thinking·app-down | floating mic | four states per spec Part 5, dark block deleted | desktop → widget |
| U8 | S6 collapsed window | zero·non-zero·read-back | count badge, confirm/discard | per spec Part 5; Moss-on-accent confirm | widget ↔ collapsed |
| U9 | Wide browser | default | 720px column cap | identical tokens, centred on Paper, no second design | any surface at 1440 |
| U10 | Desktop app launch | launch·offline·error·recovered | open installed Skippy.app | reaches live frame; honest states; behavior-proven, never launcher-hash-proven | Dock → app |
| U11 | Voice loop (OpenAI path) | success | speak → transcript → core reply → spoken back | full round trip, flags ON, ephemeral token only in browser | mic → reply |
| U12 | Voice loop | failure·interruption | provider fails / user interrupts | honest recovery, ElevenLabs rollback path still selectable | mic → error → retry |
| U13 | Dark-forced check | forced dark | re-render all surfaces | pixel-identical to light capture | all surfaces |
| U14 | Slack adapter | inbound·failure·success | one live round-trip (bot identity, never as Nick) | typed delivery outcome + recipient-view read-back | Slack → core → Slack |
| U15 | Gmail adapter | inbound·failure·success | one live round-trip, draft-only leg | typed outcome; draft visible in the real mailbox UI | Gmail → core → Gmail |
| U16 | WhatsApp adapter | inbound·failure·success | one live send + read-back (standing test scope, 2026-09-03) | typed outcome + read-back from the destination | WhatsApp → core → WhatsApp |
| U17 | Alexa adapter | invalid·failure·success | simulator run + live echo leg if reachable | typed outcome; live leg else NOT AGENT-TESTABLE with the one human ask | Alexa → core → Alexa |
| U18 | Reuse kit | n/a (headless) | cold reader applies it dry-run to a second surface | reader completes the token re-point walkthrough without a question | kit → dry run |
### TEST LAYERS — the landing spot STEPS 12–14 write into (empty until they close)
> "…then called done for skippy and are incorporated into the rest of the ksippy testing as layers to test on if needed" (Nick, 2026-09-04). When a channel's testing phase closes, its DONE line and its one-command layer invocation land HERE — so "available as a layer" is a row a later test plan can lift, not a sentence.
| Channel | DONE (date + evidence file) | Layer invocation (one command a Skippy test can run) |
|---|---|---|
| Slack | — | — |
| Gmail | — | — |
| WhatsApp | — | — |
| Alexa | — | — |
## 3 · Lanes and frozen contracts
**File fences are drawn so no two lanes ever need the same file in the same hour (skill §W). Scoped commits only (`git commit -m "..." -- <paths>`); never `git stash`; re-read a file immediately before writing it; skippy-code is its own nested repo — `cd` into it first.**
| Lane | Scope (in / out) | Owner | Definition of done | Model (explicit) |
|---|---|---|---|---|
| VOICE | In: `skippy-code/` only (server.js, public/voice.js, lib/openai-realtime-adapter.mjs). Out: every CSS file, desktop/, channels/. | voice lane builder | STEPS 2–4 proven; FINISH LINE item 1 | glm builds · sonnet checks |
| LOOK-FRAME | In: `projects/personal/family-app/css/signal-frame-window.css`, NEW font asset files it references (added under the family app's served css/fonts path — new files only, never another screen's file), and the 720px wide cap (this lane's file, this lane's work). Out: every other existing family-app file (SMP-2's ground), all of skippy-code/, desktop/. | frame reskin builder | STEPS 5–6 proven | glm builds · sonnet checks · Sienna (fable) design authority |
| LOOK-DESKTOP | In: `projects/personal/skippy-app/desktop/widget.html`, `collapsed.html` (+ their inline CSS), and in `main.js` EXACTLY the native-theme background values (the line returning `#07080a`/`#f4f4f2` — repaint to Paper, delete the dark branch; nothing else in main.js). Out: all other main.js behavior, preload files. | desktop reskin builder | STEP 7 proven | glm builds · sonnet checks |
| LOOK-SHELL | In: `skippy-code/public/index.html` + shell CSS (never voice.js — VOICE owns it; never an element id). Out: everything else. | shell reskin builder | STEP 8 proven (or corrected in place if STEP 1 proves the shell not user-facing) | glm builds · sonnet checks |
| QA-VISUAL | In: `projects/personal/skippy-app/design-directions/` (harness + evidence) — read-only everywhere else. | sweep + design QA | STEPS 9–10 proven | glm builds harness · fable (Sienna) grades · sonnet re-runs |
| CHANNELS-TEST | In: run-only against `channels/`, `wa/`, `alexa/`; writes only evidence + DONE lines. Out: adapter source edits (a real defect found → one fix step inside this lane's own fence, named file, snapshot first). | channels tester | STEPS 12–14 proven; FINISH LINE item 4 | sonnet drives live legs · glm fixes if a defect is found · sonnet re-checks |
| INTEGRATE | In: this plan file, STATE-SKIPPY-FINISH.md, PLAN-CHANGES-SKIPPY-FINISH.md, `projects/ops/skippy-master-plan/evidence/` (smp-finish-* files only). | the drive session (Fable overseer) | STEPS 1, 11, 15–17 proven | fable oversees · sonnet checks |
**Contracts between lanes (FROZEN — change = dated delta in PLAN-CHANGES-SKIPPY-FINISH.md):** the Signal-shell element-id SET is immutable, enforced as a measured list (capture the sorted unique id set before, diff after, empty diff or fail — never a bare count, since the two sources disagree 26 vs 27); the design tokens are the spec's Part 3 literals (`#ABCFAC`, `#F0E8DA`, `#F3F7ED`, `--stone-ui #786a56`, Fault `#a05f42`, Destructive `#b9603c`) — LOOK lanes consume, never redefine; **the forbidden list is the spec Part 6 check 2 list IN FULL, all 14 tokens: `#b06a00`, `#ffb43d`, `#0a7a4c`, `#4ade9b`, `#c0341f`, `#ff6b5a`, `#f4f4f2`, `#07080a`, `#14161a`, `#0d0f13`, `#1c2028`, `Adriane`, `serif`, `font-family: var(--mono) !important`** — a first draft dropped the five dark hexes, which are exactly the ones still live on disk; the Shape 2 voice invariant (transcription-only session) — VOICE lane; evidence basenames are `smp-finish-NN-*` in the shared evidence folder, one writer per file; each lane commits only paths inside its own fence.
## 3b · Execution map — the Step map, then one STEP block per row
A task is DONE only when its review-ledger row is CLOSED by a reviewer that is not the builder.
**Step map (read this first):**
| Stage | # | Task (step name) | Gate to enter | EXECUTOR (model, from the matrix) | CHECKER (different model — never the builder) | DONE-PROOF (runnable command) | Ends when |
|---|---|---|---|---|---|---|---|
| Plan | 1 | Live baseline + topology pin | nothing — start now | sonnet | glm | `ls projects/ops/skippy-master-plan/evidence` shows smp-finish-01-baseline.txt (CREATED BY STEP 1's run; checker re-lists) | honest defect list + serving topology recorded |
| Tests | 2 | Independent verification of the voice listening half + 2026-09-03 wiring | nothing — start now | sonnet | glm | `node --check projects/personal/skippy-app/skippy-code/lib/openai-realtime-adapter.mjs` plus the verifier's evidence file | listening half verified or its named defects listed |
| Tests | 3 | End-to-end real-mic conversation on the Mac, flags ON in test | STEP 2 verdict exists; STEP 1 baseline exists | sonnet | glm | `command grep -c "voiceOriginated" projects/personal/skippy-app/skippy-code/server.js` ≥1 and the live-run evidence file | one full spoken round trip recorded |
| Output | 4 | Voice go-live: flags default ON, rollback intact | STEP 3 proof | glm | sonnet | `command grep -ci "elevenlabs" projects/personal/skippy-app/skippy-code/server.js` ≥1 (rollback path still present) + flag-state read-back | Nick's real app uses the OpenAI path |
| Framing | 5 | Reskin groundwork: font load, kill mono !important, kill dark blocks | nothing — start now | glm | sonnet | `command grep -c 'font-family: var(--mono) !important' projects/personal/family-app/css/signal-frame-window.css` prints 0 | all kill-switches out, fonts loading |
| Elements | 6 | S1–S4 Deep Mint restyle (tokens, type, geometry, corrections) | STEP 5 proven | glm | sonnet | `command grep -c '#ABCFAC' projects/personal/family-app/css/signal-frame-window.css` ≥1 and forbidden-list greps print 0 | frame surfaces wear Deep Mint |
| Elements | 7 | S5 widget + S6 collapsed + native window ground | STEP 5 proven | glm | sonnet | `command grep -c '#07080a' projects/personal/skippy-app/desktop/main.js` prints 0 (2 today) + Part 5 conformance table | desktop surfaces wear Deep Mint, ground can't go dark |
| Elements | 8 | Signal shell wears Deep Mint (no id renames) | STEP 5 proven; NO-OP only on STEP 1 evidence + overseer sign-off + a line to Nick | glm | sonnet | `command grep -c '#ABCFAC' projects/personal/skippy-app/skippy-code/public/index.html` ≥1 (0 today); id-set diff empty | shell matches, ids intact |
| Tests | 9 | Build the visual sweep harness + capture the grid | STEPS 6–7 proven | glm | sonnet | `ls projects/personal/skippy-app/design-directions` shows _deep-mint-sweep.mjs (CREATED BY STEP 9's run) and its printed swept-grid line is saved | sweep prints the full grid line and saves screenshots |
| Proof | 10 | Sienna's design QA — the six checks, one round | STEP 9 proven | fable | sonnet | `node projects/personal/skippy-app/design-directions/_deep-mint-sweep.mjs` (CREATED BY STEP 9) exits 0 with the full grid line; her verdict file saved | PASS, or FAIL list handed to one fix pass (re-check named failures only) |
| Tests | 11 | Installed-app honest-states drive | STEP 4 proven; STEP 7 proven | sonnet | glm | `node --check projects/personal/skippy-app/desktop/main.js` exits 0 + behavior evidence file (never a launcher hash) | launch/offline/error/recovered proven by behavior |
| Tests | 12 | Slack + Gmail testing phase | nothing — start now | sonnet | glm | `node projects/personal/skippy-app/channels/_test-smp6-secure-boundary.mjs` exits 0; same for gmail-draft-only + provider-failure-recovery; live round-trip evidence | both recorded DONE with typed outcomes |
| Tests | 13 | WhatsApp testing phase | nothing — start now | sonnet | glm | `node projects/personal/skippy-app/wa/_test-smp7-secure-boundary.mjs` exits 0 + live send/read-back evidence | recorded DONE with typed outcome |
| Tests | 14 | Alexa testing phase | nothing — start now | sonnet | glm | `node projects/personal/skippy-app/alexa/test-adapter.mjs` exits 0 and `node projects/personal/skippy-app/alexa/test-schema.mjs` exits 0 + simulator/live-leg evidence | recorded DONE, or honest NOT AGENT-TESTABLE with the one human ask |
| Details | 15 | Reuse kit for Hub + family app | STEPS 6–7 proven (pattern must exist to document) | glm | sonnet (cold reader) | `ls projects/personal/skippy-app/design-directions` shows DEEP-MINT-REUSE-KIT.md (CREATED BY STEP 15's run); cold reader's dry-run note saved | a cold reader applied it without a question |
| Proof | 16 | Blind final QA — all 18 manifest rows re-run; DONE = 18/18 pass | STEPS 1–15 proven (all FINISH LINE inputs exist) | sonnet (fresh session, never saw the build) | fable (relays verdict unchanged) | `python3 projects/ops/agents/check_plan.py projects/ops/skippy-master-plan/PLAN-SKIPPY-FINISH.md` (repo root; overseer's own hygiene check) exits 0 + the blind verdict file grading every §2 row | verdict recorded unchanged; DONE at 18/18 pass, else NOT DONE with the named gaps to Nick |
| Proof | 17 | Postmortem + NEXT list + registry append | STEP 16 verdict recorded | fable | sonnet | `command grep -c "POSTMORTEM" projects/ops/skippy-master-plan/PLAN-SKIPPY-FINISH.md` (repo root) ≥1 after the edit | postmortem in this plan; registry appended; drive closed |
**Then one block per step:**
### STEP 1 — Live baseline + topology pin
**Enter this step when:** nothing. This is a first step. **RUNNABLE WHEN:** the Mac screen is unlocked (probe it; locked = record WAITING FOR THE MAC TO BE UNLOCKED, take another first step).
**Builder:** sonnet (verification-shaped work) · **Checker:** glm, different session.
**Files you may touch:** `projects/ops/skippy-master-plan/evidence/` smp-finish-01-* files only. **Never** any product file.
**Do exactly this:**
1. Preflight instruments and paste exit codes: DNS answer non-empty · bind a local port · window-server count · one write+read-back in the repo. Any probe failing → every verdict this step produces is NOT MEASURABLE FROM HERE, named — never a product FAIL.
2. Open the installed Skippy.app from /Applications; drive one typed conversation turn and one voice attempt on the real screen; screenshot each state to the evidence folder (durable, never /tmp).
3. Pin the serving topology as a V2 fact: which process serves the voice UI Nick uses (the running server.js pid 996's routes vs the frame URL), recorded as `opened <what>, saw: <what>`.
4. Write the honest defect list — what works today, what does not — one line each, into smp-finish-01-baseline.txt. An empty defect list requires a second, differently-shaped check before it stands (skill §Z).
**PROOF:** the baseline file exists in the evidence folder with ≥1 screenshot artifact; the topology line uses the V2 form; each defect names what was driven, at which width. FAILS IF: the file describes reasoning instead of a drive, or cites no artifact.
**If it fails:** one line to the overseer; STEPS 2, 5, 12–14 are all independently runnable — take one.
**Checker's job:** re-open the artifacts and re-run one drive first-hand. Do not accept the pasted output.
### STEP 2 — Independent verification of the listening half + the 2026-09-03 wiring
**Enter this step when:** nothing. This is a first step.
**Builder:** sonnet, a session that has never touched the voice code · **Checker:** glm re-runs the checks.
**Files you may touch:** evidence smp-finish-02-* only. Read-only on skippy-code.
**Do exactly this:**
1. Start from the verification that already exists: `projects/ops/skippy-master-plan/evidence/smp-1-07-listening-independent-verify-claude-2-0-c0.md` (2026-09-03). Do NOT redo what it closed. Its two open ends are this step's actual work:
2. RE-VERIFY THE FIX for the defect it found (`close()` deadlocking a pending `next()` — its own text says re-verification never completed): reproduce the original failing case against the current code, first-hand.
3. Verify the path that SHIPS, not just the reference function — c0 records that `startOpenAIListeningSession` is not what runs in this architecture; the browser-side connection in `skippy-code/public/voice.js` is. Check the wiring proof's claims (`projects/ops/skippy-master-plan/evidence/smp-1-07-wiring-local-proof.md`) against the real files with real calls where keys allow, never a re-read of the builder's claims.
4. Attack the Shape 2 invariant once: confirm a `response.create` against the transcription session is refused by name.
**PROOF:** verdict file smp-finish-02-listening-verify.md with per-check PASS/FAIL, the deadlock-fix re-verification result, and the invariant refusal shown. FAILS IF: any check is answered from the builder's own text, or the deadlock fix is assumed verified because a fix exists.
**If it fails (real defects):** defects go to STEP 3's builder as its first work items; the step is still DONE when the verdict is honest.
**Checker's job:** re-run two of the checks first-hand, including the invariant attack.
### STEP 3 — End-to-end real-mic conversation, flags ON in test
**Enter this step when:** STEP 2's verdict file exists (ANSWERED is enough; a FAIL list feeds this step) and STEP 1's baseline exists.
**Builder:** sonnet drives; glm builds any fix this step needs (each fix: one named file inside the VOICE fence, snapshot first, scoped commit inside skippy-code) · **Checker:** glm re-drives.
**Files you may touch:** `skippy-code/server.js`, `skippy-code/public/voice.js`, `skippy-code/lib/openai-realtime-adapter.mjs` (fixes only); evidence smp-finish-03-*. **Never** `lib/conversation-ledger.mjs`, `public/vendor/` (ElevenLabs stays as rollback), any desktop/ or css file.
**Do exactly this:**
1. Enable both voice flags in a test window on the real Mac (agents drive his machine and identity gates under standing authorization — do not re-ask).
2. Speak a real sentence into the live mic; confirm the transcript event arrives, the reply comes from the existing chat pipeline with `voiceOriginated: true`, and the reply is spoken back through the TTS branch.
3. Interrupt mid-reply once and force one provider failure (bad key in test scope only — never touch the real stored key); confirm honest recovery both times.
4. Save the run log + screenshots durable; record latency measured, not estimated.
**PROOF:** smp-finish-03-e2e.md records one full spoken round trip with artifacts, one interruption, one failure-recovery. FAILS IF any of these observable stand-ins for his complaint is true: a click or keypress was needed anywhere between starting to speak and hearing the reply · the reply was never audibly spoken · the transcript sent to the core does not match the sentence spoken · a second consecutive turn could not follow without touching anything. (These four operationalize "we chat back and forth without clicking buttons" — a run can pass its mechanism and still fail here, which is the point.)
**If it fails:** the named defect goes back to the builder once; re-check the named failure only; other steps continue.
**Checker's job:** re-drive one spoken turn first-hand on the same Mac.
### STEP 4 — Voice go-live
**Enter this step when:** STEP 3 proven. Sheet row 6 governs: default is flip-on-pass; if Nick answered "show me first," this step waits for his word and everything else continues.
**Builder:** glm · **Checker:** sonnet.
**Files you may touch:** the flag defaults in `skippy-code/server.js` / `skippy-code/public/voice.js` only; evidence smp-finish-04-*.
**Do exactly this:** flip the two feature-flag defaults ON; scoped commit inside skippy-code naming exactly what changed; restart the server path the way it is normally run; confirm the running process serves the new defaults (read back from the running thing, not the file).
**PROOF:** flag state read back from the live process; one post-flip spoken turn succeeds; ElevenLabs branch still selectable (rollback intact, grep ≥1). FAILS IF: read-back comes from the file instead of the process.
**If it fails:** flip back (the rollback is the point), one line to the overseer.
**Checker's job:** re-read the live flag state and speak one turn.
### STEP 5 — Reskin groundwork
**Enter this step when:** nothing. This is a first step (different fence from VOICE).
**Builder:** glm · **Checker:** sonnet.
**Files you may touch:** `projects/personal/family-app/css/signal-frame-window.css`, `projects/personal/skippy-app/desktop/widget.html`, `projects/personal/skippy-app/desktop/collapsed.html`, the font assets the CSS references. **Never** any other family-app file (SMP-2's ground), never main.js.
**Do exactly this:**
1. DELETE (not override) the `font-family: var(--mono) !important` block in signal-frame-window.css (measured present, count 1, 2026-09-04 — re-measure first; the spec's line numbers are stale).
2. Re-measure the dark blocks in widget.html and collapsed.html — measured ALREADY CLEAN 2026-09-04 (`color-scheme: light` present at widget.html:36 / collapsed.html:37, zero `prefers-color-scheme`); if the re-measure agrees, record it and touch nothing there. THEN close the dark hole those files can't fix: hand LOOK-DESKTOP its one main.js edit (the native-theme background returning `#07080a` in dark — repaint to Paper, delete the dark branch) so the native window ground can never go dark.
3. Load Neue Montreal as a real webfont with Inter properly loaded as fallback (sheet row 3 default) — no silent system fallback. Reality on disk: only `NeueMontreal-Medium.woff` exists, one weight, outside the served tree. Fetch the 400/700 weights from the brand website's copy (named in the spec) and add them as new font files under the family app's served css/fonts path (fence allows exactly this). If only Medium is genuinely obtainable after two differently-shaped attempts, load Medium + proper Inter for the missing weights and put the gap on the sheet — never a silent fallback.
4. Snapshot each file (`*.pre-deepmint-20260904.bak`) before its first edit; scoped commits.
**PROOF:** the three greps in the step map print 0 for the killed blocks; a computed-style read on a running page resolves to the loaded font, not a fallback. FAILS IF: the mono block is overridden rather than deleted.
**If it fails:** one line to the overseer; STEP 12–14 remain runnable.
**Checker's job:** re-run the greps and the computed-font read first-hand.
### STEP 6 — S1–S4 Deep Mint restyle
**Enter this step when:** STEP 5 proven.
**Builder:** glm · **Checker:** sonnet · **Design authority:** Sienna's spec Parts 3–4 verbatim — the builder implements, never invents.
**Files you may touch:** `projects/personal/family-app/css/signal-frame-window.css` only.
**Do exactly this:** 🔴 the token work is PARTLY LANDED already (Already true) — so this step is a spec-conformance pass, not a from-zero paint, and its proof must be able to fail on today's file. (1) Walk spec §3.2–3.5 + Part 4 row by row against the file: every literal (the two derived colours, `--stone-ui #786a56` below 14px, Fault `#a05f42`, Destructive `#b9603c`, status colours collapsed into the accent, every pip's text label, header 69px/4px-accent border, bubble radius 14, dock geometry) either present or edited in, extending the proven re-pointing pattern (the Tulum Natural skin, per the spec) — never a new mechanism, never an id or class rename (measured-list contract). (2) Implement the wide-browser rule (spec Part 5 tail): content column capped at 720px, centred on Paper above that width, no second design — this file, this lane. (3) Record the per-row conformance table (spec row → present-already / edited / N/A-with-reason) as this step's evidence file.
**PROOF:** the conformance table covers every spec §3.2–3.5 + Part 4 row with zero rows left open; `#ABCFAC` ≥1 and `#F0E8DA` ≥1; the FULL 14-token forbidden list (§3 contract) greps 0 in this file; id-set diff empty. FAILS IF: any spec row is marked present without its literal value quoted from the file, or any forbidden token survives. (The full forbidden list CAN fail today — the dark hexes are live elsewhere — and the conformance table can fail on any missed geometry row; the old grep-only proof passed on the unedited file and was replaced for exactly that reason.)
**If it fails:** fix in place; the named row is the re-check.
**Checker's job:** re-run every grep first-hand; re-derive five random conformance rows from the file, including two geometry values measured in a rendered page.
### STEP 7 — S5 widget + S6 collapsed + the native window ground
**Enter this step when:** STEP 5 proven. (The 720px wide cap is STEP 6's work — LOOK-FRAME's file, LOOK-FRAME's lane; a first draft split one file across two lanes and the cold reader caught it.)
**Builder:** glm · **Checker:** sonnet.
**Files you may touch:** `projects/personal/skippy-app/desktop/widget.html`, `collapsed.html` (inline CSS), and in `main.js` ONLY the native-theme background values (the dark branch returning `#07080a` — repaint to Paper `#fffdf8`, delete the branch; nothing else).
**Do exactly this:** 🔴 widget/collapsed already carry the light lock and accent tokens (Already true) — this is a conformance pass against spec Part 5, row by row: widget four states at 40×40 (resting `#F3F7ED`+accent border, listening accent fill, thinking `#D9E8D7`, app-down Fault), collapsed 64×64 with the count badge, NEW label in `--stone-ui`, read-back overlay with Moss-on-accent Confirm; then the main.js dark-branch repaint. Record the same per-row conformance table as STEP 6.
**PROOF:** conformance table covers every Part 5 row for S5+S6, zero open; the FULL forbidden list greps 0 across widget.html, collapsed.html AND main.js — main.js measures 2 dark-hex hits TODAY, so this proof fails until the repaint lands. FAILS IF: any state carries meaning by colour alone, or main.js still contains `#07080a`.
**If it fails:** fix in place, re-check named failures.
**Checker's job:** re-run greps incl. main.js; render the widget's four states first-hand.
### STEP 8 — Signal shell wears Deep Mint
**Enter this step when:** STEP 5 proven. 🔴 DEFAULT IS DO THE WORK — the shell is the LEAST-painted Skippy surface on disk (`#ABCFAC` count 0, one dark hex live, measured 2026-09-04), so skipping it risks skipping the one screen that needs real paint. The NO-OP path exists but is narrow: only if STEP 1's topology pin proves with cited evidence that Nick never opens this screen, AND the overseer signs the NO-OP, AND a plain-English line goes to Nick ("this screen looks unused — say the word and it gets painted too"); then correct this step in place with the evidence, log the delta.
**Builder:** glm · **Checker:** sonnet.
**Files you may touch:** `skippy-code/public/index.html` shell styling only. **Never** voice.js (VOICE lane's file), never an element id.
**Do exactly this:** capture the shell's sorted unique element-id set (from index.html + the ids app.js/voice.js reach for — read-only on those two); apply the same Part 3 tokens to the shell's styles; re-capture the id set; diff.
**PROOF:** `#ABCFAC` ≥1 in the file (0 today — this proof fails until the work lands); id-set diff EMPTY; full forbidden list greps 0 (1 dark hex today). FAILS IF: the id-set diff is non-empty, or "unchanged count" is offered instead of the set diff.
**If it fails:** revert from snapshot, one line to the overseer.
**Checker's job:** re-run the id-set capture + diff and two forbidden-token greps first-hand.
### STEP 9 — Visual sweep harness + capture
**Enter this step when:** STEPS 6 and 7 proven.
**Builder:** glm · **Checker:** sonnet.
**Files you may touch:** `projects/personal/skippy-app/design-directions/` — new file _deep-mint-sweep.mjs + screenshots into a new evidence subfolder there (durable, never /tmp).
**Do exactly this:** build the sweep per spec Part 6 check 5: it renders every surface (S1–S6 + wide) at widths 390/720/1440, light and dark-forced, every §2 state, samples the two pass/fail pixels (`#ABCFAC` at the mic centre, `#F0E8DA` at a user bubble), greps the forbidden list, and prints the literal swept-grid line naming surfaces × widths × schemes × states. Prove it can fail: sabotage one token in a scratch copy, watch it redden, restore, record both runs.
**PROOF:** the harness exists, exits 0 on the real tree, its printed grid line matches the spec's full grid, and its red-proof run is recorded. FAILS IF: the grid line names fewer cells than the spec (a quick sweep reading as a clean suite is the known trap).
**If it fails:** one line to the overseer; Sienna's step waits, everything else continues.
**Checker's job:** re-run the harness first-hand and read the grid line against the spec, not the word PASS.
### STEP 10 — Sienna's design QA, one round
**Enter this step when:** STEP 9 proven.
**Builder (grader):** fable — Sienna (`creative-director`), against `voice-options.html`, all six checks in spec Part 6, every claim naming width and theme · **Checker:** sonnet re-runs the harness and re-reads two screenshots.
**Files you may touch:** her verdict file in design-directions/ only.
**Do exactly this:** run all six checks including check 6 (a human-eye pass over every screenshot, side by side with the mockup) and check 4 (dark-forced pixel-identity). One round: PASS closes; FAIL returns the named failures to the owning LOOK lane once, and the re-check covers the named failures only — no fresh full sweep, no second adversary.
**PROOF:** her verdict file lists each of the six checks with evidence per check. FAILS IF: any check is graded from the builder's paste.
**If it fails:** the one fix pass runs; her re-check of named failures lands; then this step closes on that verdict, whatever it is, and anything residual goes to the NEXT list.
**Checker's job:** re-run the sweep; confirm the screenshots she graded are the ones on disk.
### STEP 11 — Installed-app honest states
**Enter this step when:** STEP 4 proven and STEP 7 proven.
**Builder:** sonnet drives; glm fixes inside `projects/personal/skippy-app/desktop/` only (main.js behavior) · **Checker:** glm re-drives (fix author never checks its own fix; where glm both fixed and would check, the checker is sonnet from a fresh session).
**Files you may touch:** desktop/ only; evidence smp-finish-11-*.
**Do exactly this:** on the installed app — launch to a visible window (the offscreen-launch trap is known; visibility is asserted on screen, not by the harness's own print), complete one conversation turn, cut the network and confirm the honest offline state, restore and confirm recovery, force one provider error and confirm the honest error state. Prove by behavior and screenshots. Never cite a launcher hash — the installed launcher is a stock binary and hashing it proves nothing (measured 2026-09-01).
**PROOF:** smp-finish-11-desktop.md with an artifact per state. FAILS IF: any state is proven by code-reading or exit code alone.
**If it fails:** defect list to glm, one fix pass, re-drive named states.
**Checker's job:** re-drive launch + offline first-hand.
### STEP 12 — Slack + Gmail testing phase
**Enter this step when:** nothing. This is a first step.
**Builder:** sonnet · **Checker:** glm.
**Files you may touch:** evidence smp-finish-12-*; a defect fix (if any) is one named file in `channels/`, snapshot first.
**Do exactly this:**
1. Re-run first-hand: the three `_test-smp6-*.mjs` harnesses (all measured exit 0 on 2026-09-04 — re-run anyway; an audit means re-running the proof).
2. One live Slack round-trip under Skippy's own bot identity — NEVER as Nick (a message as Nick to another human is approval class 4); read the message back FROM Slack's own API, not the send receipt.
3. One live Gmail leg, draft-only (the draft-only harness is the built shape): create a real draft, read it back from the mailbox, delete the draft.
4. Record each with its typed delivery outcome; write the DONE line + test-layer line (STEP 16 consumes them).
**PROOF:** three harness exits 0 + two live read-backs with artifacts. FAILS IF: an acknowledgement (`ok:true`/`queued`) stands in for a destination read-back.
**If it fails:** the named defect → one glm fix inside the fence → re-run the named harness + leg.
**Checker's job:** re-run one harness and re-read both destinations first-hand.
### STEP 13 — WhatsApp testing phase
**Enter this step when:** nothing. This is a first step.
**Builder:** sonnet · **Checker:** glm.
**Files you may touch:** evidence smp-finish-13-*; a defect fix is one named file in `wa/`, snapshot first.
**Do exactly this:** re-run `_test-smp7-secure-boundary.mjs` plus the dedupe, thread-context and provider-failure-recovery harnesses in `wa/` first-hand; then one live send and read-back (standing scope, locked 2026-09-03: recipient among Nick/Chantelle and message content never matter for a WhatsApp test send — do not re-ask); typed outcome recorded; DONE + layer lines written.
**PROOF:** harness exits 0 + live read-back from the destination with artifact. FAILS IF: the live leg's proof is the sender's own receipt.
**If it fails:** named defect → one fix → named re-run.
**Checker's job:** re-run the boundary harness and re-read the destination.
### STEP 14 — Alexa testing phase
**Enter this step when:** nothing. This is a first step.
**Builder:** sonnet · **Checker:** glm.
**Files you may touch:** evidence smp-finish-14-*; a defect fix is one named file in `alexa/`, snapshot first.
**Do exactly this:** re-run the SEVEN runnable `alexa/` tests by name — test-adapter, test-schema, test-auth, test-bounds, test-no-action, test-device-discovery, test-console-receipt — plus `simulator.mjs`, first-hand (adapter and schema measured exit 0 on 2026-09-04; `test-fixtures.mjs` is a fixtures module, not a test, and counts for nothing); then attempt the live echo-device leg. If the device leg is genuinely beyond any agent instrument after three differently-shaped attempts, record it NOT AGENT-TESTABLE and write the ONE consolidated human ask (what Nick should say to the device and what he should observe) — gathered with any other human-owned item into a single ask, never N. Typed outcome recorded; DONE + layer lines written. Alexa's testing phase is in scope by Nick's own later word ("compile that into one list with alexa", 2026-09-04) — building anything new for Alexa is not.
**PROOF:** test exits 0 across the suite + simulator artifact + the live leg's evidence state declared as exactly one of the six evidence states. FAILS IF: NOT AGENT-TESTABLE is declared without the three named attempts.
**If it fails:** named defect → one fix → named re-run.
**Checker's job:** re-run two of the eight tests and the simulator.
### STEP 15 — The reuse kit
**Enter this step when:** STEPS 6 and 7 proven (the pattern must exist before it is documented).
**Builder:** glm · **Checker:** sonnet acting as the cold reader.
**Files you may touch:** new file DEEP-MINT-REUSE-KIT.md in `projects/personal/skippy-app/design-directions/`, and one appended handoff line in `projects/ops/zion/STATE-ZION-19.md` §HANDOFFS-IN (workspace repo — that one line only, never any other part of the Hub lane's files).
🔴 **THIS KIT OWNS THE VOICE SETUP, NOT ONLY THE LOOK — RULED 2026-09-04 BY THE CROSS-PLAN COLD REVIEW.** All three drive plans were read together and this was the one gap none of them owned: the Hub plan's STEP 11 waits on "the voice-app lane's reusable voice-pattern artifact", while this kit was written design-only — tokens, fonts, kill-list, sweep — with nothing about voice in it. Nobody built it. The ruling rests on Nick's own words, *"finish voice app then we deploy the same etup in the hub and family app"* (2026-09-04): "the setup" is the VOICE setup, and it is built once, in the lane that builds voice. A design-only kit leaves the Hub and family app to invent voice twice, which is the duplication he named.
**Do exactly this:**
1. Write the DESIGN half as already specified — numbered, literal instructions for wearing this setup on another surface: the token table (mockup name → value → the target app's own token to re-point), the re-pointing pattern with a real before/after example from this build, the kill-list (mono !important, dark blocks, forbidden colours, the ?v= cache-bump rule for any versioned asset), the font-loading step, the id-immutability rule, and the sweep-harness invocation as the acceptance check.
2. Write the VOICE half, to the same standard, covering what another surface must reproduce to run this voice setup: the feature flags and their default states · how a short-lived session token is minted and where that minting must live · the server-side and browser-side wiring, named file by file as they exist in THIS build · the transcription-only invariant and what would violate it · the permission states the surface must handle, including denied-microphone · and the rollback — how to switch it off cleanly on a surface where it misbehaves.
3. Append ONE dated handoff line to `projects/ops/zion/STATE-ZION-19.md` under §HANDOFFS-IN, naming this kit's real path and the specific voice files the Hub is to port. That single line is the Hub plan's named entry condition for its STEP 11 — until it exists that step is queued, so this step's close is what releases it.
**PROOF:** the cold reader (a sonnet session that never saw this build) walks the kit dry-run against one family-app non-Skippy screen for the design half AND derives the voice port for one named Hub surface — deriving the edits WITHOUT making them — and files zero questions. FAILS IF: the reader had to open this plan to proceed, or the voice half names no real file that exists in this build. Separately, `command grep -n "HANDOFFS-IN" -A 20 projects/ops/zion/STATE-ZION-19.md` shows the dated line with this kit's path in it.
**If it fails:** each question becomes a kit edit; one re-read. If the voice half cannot be written because the voice build is not finished, this step waits on the voice steps rather than shipping a design-only kit under a name that promises both — and the Hub plan is told, in that same handoff line, that it is design-only so far.
**Checker's job:** the cold read IS the check, and it now covers both halves. Confirm the handoff line actually landed in the Hub lane's state file — a kit nobody is told about is the same as no kit.
### STEP 16 — Blind final QA
**Enter this step when:** STEPS 1–15 each carry their proof (a FAIL honestly recorded in 10 or 14 does not block entry; the blind checker grades what is).
**Builder:** a fresh sonnet session that has never seen this drive, handed ONLY the FINISH LINE, the §2 manifest and the artifact paths — it never opens this plan and never edits anything (that is what keeps it blind) · **Checker:** fable (the overseer) relays the verdict UNCHANGED — an edited relay is the self-grading this step exists to prevent.
**Files you may touch:** blind checker — its verdict file in evidence, nothing else. Overseer — this plan's STEPS statuses afterwards, plus running `python3 projects/ops/agents/check_plan.py projects/ops/skippy-master-plan/PLAN-SKIPPY-FINISH.md` from the repo root (the overseer's own hygiene check, deliberately NOT the blind checker's job).
**Do exactly this:** the blind checker re-runs every §2 row's proof first-hand — audit means RE-RUN, never recite — and returns pass/fail per row with evidence. All proof commands run from the repo root. Coverage is verified ÷ total with the denominator pinned at the §2 row count (18); no rows are added mid-drive.
**PROOF:** verdict file grades 18 of 18 manifest rows (every row EXECUTED). 🔴 DONE means 18/18 PASS — an execution count is never a pass count. FAILS IF: any row's verdict rests on a builder's paste.
**If it fails (rows fail):** each failing row gets one fix pass by its owning lane, one named re-check. If anything still fails after that round, the drive reports NOT DONE to Nick with the exact count and the named gaps — it never closes as "done at 12/18"; only Nick can accept a shortfall.
**Checker's job:** relay, unchanged, including anything that fails this plan's own spec.
### STEP 17 — Postmortem, NEXT list, close
**Enter this step when:** STEP 16's verdict is recorded.
**Builder:** fable (overseer) · **Checker:** sonnet confirms the postmortem exists and the registry append landed.
**Files you may touch:** this plan (POSTMORTEM + NEXT sections, STEPS statuses), `.claude/skills/plan/references/failure-registry.md` (append only — dry-run the registry count first; appending an entry raises every clean plan's §4 bar, so the same edit adds this plan's covering row), PLAN-CHANGES-SKIPPY-FINISH.md.
**Do exactly this:** write the postmortem INTO this plan (every failure, every stale step corrected, what to keep); put everything anyone still wants on the NEXT list — including the click-gated security pass, Gracie/Neeko, and the Hub/family-app deployments of the reuse kit; hand the DONE summary to Nick in plain English.
**PROOF:** grep for POSTMORTEM in this plan ≥1; NEXT list present; registry append (if any) paired with its covering row in the same commit, scoped.
**If it fails:** it cannot — writing honestly is the step.
**Checker's job:** confirm both halves of any registry append landed together.
## 4 · Regret Check (every registry entry, or the plan is not done)
*One row per registry entry, in registry order (PLANNING → DECOMPOSITION → EXECUTION → INTEGRATION → QA → REPORTING → the ten retro blocks). "Steps" below are this plan's §3b steps.*
| Failure mode (registry entry) | The measure in THIS plan that prevents it | Where it lives |
|---|---|---|
| A second system was built because the first was invisible | Nothing new is built beside the estate; channels get testing, not construction; ownership receipt cites the estate | §0, anti-scope |
| A capability declared impossible from a stale claim | Every impossibility is re-tested (Alexa "0%" refuted on disk; live surface re-probed) | Already true, STEP 1 |
| An absence asserted without opening the store | §Z rule binds every negative; STEP 2 searches two ways before "no verdict exists" | STEP 1.4, STEP 2.1 |
| A constraint's reason lost, silently capping the product | Every constraint carried names its reason (Shape 2, 27 ids, ElevenLabs rollback) | §3 contracts |
| An instruction assumed capacity the executor lacks | Briefs are per-step and self-contained; no whole-guide reads required | §3b blocks |
| Manifest rows carried no grounding | Every §2 row maps to a spec/state source and a step | §2 |
| Work written to a queue no reader visits | Every artifact names its consumer (STEP 16 consumes DONE lines; kit consumed by Hub plan) | §5 artefact consumers |
| A detector's death invisible to itself | The sweep harness carries a red-proof; watchers are not built here | STEP 9 |
| A settled decision re-opened, or two rule copies disagreeing | One spec is authority (Deep Mint spec); FINDINGS.md amendment routed, not duplicated | §1, NEXT |
| A rule constraining the user turned out invented | Every ruling here carries Nick's dated verbatim words | throughout |
| Remediation ordered with diagnosis last | STEP 1 is the is-it-already-fine check before any fix | STEP 1 |
| A document believed over the live system | Old plan claims rejected; disk + live measurements only; STEP 1 re-pins | Already true |
| A proposal sold on a capability never opened | voiceOriginated/`/api/chat` reuse was confirmed by reading the real code (handoff v3) | Already true |
| A cause acted on without eliminating alternatives | Failure states in steps demand controls; NOT MEASURABLE never becomes FAIL | STEP 1.1 |
| The human asked what the record answers | Sheet carries only V1s; V2s were opened instead | §1a |
| Spec and guard authored by one hand ratifying a defect | Sienna's spec grades a build she didn't build; blind QA never saw the drive | STEPS 10, 16 |
| Session rules never reached subagents | Every dispatch carries the §T header + pasted machine-rules substance | §5 |
| One rule blanket-applied across per-item answers | Each channel gets its own step, fence and typed outcome | STEPS 12–14 |
| Loose pattern-matching produced false connections | Greps anchor on declarations and exact literals, not shapes | step proofs |
| Rules psychologically dormant at answer-time | STEP 0's five-minute loop re-fires the four rules | STEP 0 |
| A run exceeded cost/time ceilings unbounded | Concurrency caps 8/session · ~40 machine-wide; waves never stack | §5 |
| A helper dispatched with a wrong default | Every example command names its literal target; no defaults | §3b blocks |
| A claim made without its source | Every Already-true fact carries a path or a dated measurement | Already true |
| A conclusion drawn from a partial read | Registry read in full (both halves); spec read in full | §0 |
| A fact quoted as current without its date | Every measurement here is dated 2026-09-04 or carries its source date | throughout |
| A computed value never reached the persistent record | Evidence files are written before reports; durable paths only | step proofs |
| A missing lookup key fell back silently | Font loading forbids silent fallback; flags read back from the process | STEPS 4–5 |
| A hardcoded identifier broke on recreation | Fences name paths, not ids; the 27 ids are asserted by count | §3 |
| A placeholder path shipped as literal | check_plan's dead-proof scan gates this file; all cited paths verified on disk | §0 |
| UI success read from the wrong layer | Server-side success is not success — behavior on the installed app, sweep pixels | STEPS 10–11 |
| Mid-session state assumed unchanged | Steps re-measure before editing (STEP 5 re-measures the stale line numbers) | STEP 5 |
| Uncertainty silently absorbed | Evidence declares one of the six states, always | step proofs |
| A serial operation blew its time budget | Independent steps (1,2,5,12,13,14) start in parallel under the cap | §3b gates |
| An external action unlogged and unrecoverable | Live legs log id + destination read-back same turn | STEPS 12–14 |
| A tool's description beat house reality | House rules named inline where they bind (WhatsApp scope, class 4) | STEPS 12–13 |
| Personal data exposed / wrong-subject write | No health/credential data moves here; sends are bot-identity or draft-only | STEPS 12–14 |
| One instance fixed while siblings stayed broken | Forbidden-list greps run per file across all surfaces, same step | STEPS 6–8 |
| A read operation mutated state | Baseline and QA steps are read-only by fence | §3 |
| Empty result / broken probe / discarded stderr | Preflight probes + known-good controls before any negative | STEP 1.1 |
| A generated mirror hand-edited | No generated file is edited; N/A: none touched — the ban is restated in the fences | §3 |
| Deployed config diverged from source | Flag state read back from the running process, not the file | STEP 4 |
| A delivery path reordered changed notification behavior | ElevenLabs path untouched; addition, not removal | STEP 3 fence |
| A critical boundary config-editable | Shape 2 is structural (transcription-only session), attacked once to prove it | STEP 2.3 |
| A "growing" archive had frozen | N/A: no store claiming freshness is created here | anti-scope |
| Files archived, citations left dangling | Supersession markers routed to one coordinator hand with the citation sweep | header |
| A pipeline broke silently, indistinguishable from working | Every step leaves a dated evidence file; silence fails the step | step proofs |
| Output delivered where the reader never looks | Read-back FROM the destination is each live leg's proof | STEPS 12–14 |
| Concurrent sessions clobbered a shared file | §W fences: no two lanes share a file in the same hour; scoped commits; no stash | §3 |
| A gate covered fewer paths than its rule | The sweep grid line is read against the spec, never trusted | STEP 9 |
| Identity read from a caller-supplied value | Voice tokens are ephemeral, minted server-side; real key never reaches the browser | STEP 3 |
| A failure state detected but reaching no human | Blind verdict + plain-English DONE summary reach Nick | STEPS 16–17 |
| The builder graded its own work | Checker ≠ builder on every row; blind final QA; Sienna grades others' work | §3b |
| A check existed that could not fail | Sweep red-proof required; harness re-runs are first-hand | STEP 9 |
| The review didn't cover the shipped artifact | Blind QA is last; any byte after it voids it | STEP 16 |
| A narrowing change broke correct cases | Reskin re-points tokens only; id count asserted before/after | STEPS 6–8 |
| A verdict depended on wall-clock or load | Live legs read event logs, not point-in-time state | STEPS 12–14 |
| A test existed but nothing ran it | Every harness in this plan is re-run first-hand in a step | STEPS 9, 12–14 |
| An interactive element shipped unseen | Check 6: a human eye over every screenshot, both widths | STEP 10 |
| Coverage reported optimistically | Coverage = verified ÷ 18, denominator pinned | STEP 16 |
| Staleness checked by the wrong proxy | Content greps and behavior, never mtimes | step proofs |
| A quantitative claim without its method | Latency "measured, not estimated"; counts carry their commands | STEP 3.4 |
| Done declared before the live surface | FINISH LINE items are all live-surface facts | FINISH LINE |
| A metric overrode felt-state | The e2e proof is Nick's own sentence, failing while it stays true | STEP 3 |
| Correlation asserted as cause | N/A: no causal analytics in this drive | — |
| Nuance collapsed into a binary | Evidence states are six-valued, never pass/fail-only | step proofs |
| A recommendation repeated something tried | Voice design carries its two live-discovered fixes so they aren't re-learned | Already true |
| A wrong record disclaimed instead of corrected | Stale steps are corrected in place, logged (STEP 8's NO-OP path) | STEP 8 |
| Open items re-typed from memory | STEPS statuses are edited in place from evidence | STEPS |
| A deliverable referenced instead of delivered | Nick's summary is plain English with the thing, not paths | STEP 17 |
| A report in writer-only shorthand | Plain-English rule binds the handback; no codenames to Nick | STEP 17 |
| Commands sent to a surface that can't run them | Human ask (Alexa) states what to say and observe, not commands | STEP 14 |
| A number without its population | 18-row denominator named wherever coverage is quoted | STEP 16 |
| A finding that died with the session | Evidence written to disk before any report, durable paths | step proofs |
| A precise plan aimed at the wrong target | SURFACE row is V1, his dated words; skippy-cloud named as the past failure | §1a row 1 |
| A summary silent on the deciding variable | The sheet is GENERATED from §1a by render_sheet.py, never hand-written | §1a |
| Scope stated without anti-scope, lanes leaking | Seven-entry anti-scope with reasons + trip-over protocol | §1 |
| A rule written as prose with nothing enforcing | This plan's rules ride existing mechanical gates (check_plan, sweep, greps) | §3b |
| A confirmation satisfied by the wrong kind of fact | Where-it-lands rows are person-confirmed; locations are V2-opened | §1a |
| A common blocker carved out to nobody | Everything removed from scope carries a named owner | anti-scope |
| Lanes built to stop; ceremony ate the context | Continuation cadence in every lane (finish → next from queue); ceremony scales | §5 |
| An unmeasured caveat travelled as fact | Load-bearing facts carry re-measure commands | Already true |
| The environment destroyed work silently | §W rules verbatim: scoped commits, re-read before write, no stash, writability probe | §3 |
| One lifecycle described in several drifting copies | The spec is the single token source; this plan cites, never restates values twice | §3 contracts |
| A task brief treated as the plan | This file's header names it the only planning document | header |
| A red-proof failing for an unrelated reason | Red-proofs run an unsabotaged control first (sweep sabotage protocol) | STEP 9 |
| Cheap-routing eroded into doing the work directly | The loop's CHEAP question re-fires every five minutes | STEP 0 |
| A plan's second line named an unopened authority | Every authority named here was opened; the spec was read in full | §0 |
| Three confident wrong diagnoses claiming live verification | V2 form mandatory; execution evidence from the running thing | STEP 1.3 |
| Guards green while the live screen was wrong | Delivery-verification rows exist (registered client, installed app) | U10–U13 |
| Fabrication accused off a narrow search | Negatives need two differently-shaped searches (§Z) | STEP 2.1 |
| A tool's verdict believed without checking the disk | Checkers re-run first-hand; disk checked after every vendor run | §3b |
| A monolith too large for one agent | Bounded steps, one fence each; single-subproject ruled with reason | §1b |
| A prose-only rule behaving as if absent | N/A here: this plan adds no new rule without an existing mechanical gate | §3b |
| A row-quality check counting cells not columns | check_plan's named-column checks gate this file itself | §0 |
| Three readers, three "% complete" for one state | The only completion figure is STEP 16's manifest math | STEP 16 |
| A V2 confirmed against the plan's own stale path | WHERE claims confirmed by fresh search (fonts, files globbed fresh) | §0 |
| A shared coordination file with no write fence | Evidence basenames one-writer-per-file; lanes commit own paths only | §3 contracts |
| The cheapest decisive test run last | STEP 1 (does it work today) and STEP 2 (is the wiring real) run first | §3b order |
| An interim status reported as a final answer | Live legs run foreground to completion; "in progress" never final | STEPS 12–14 |
| A sandbox error misread as a known machine failure | Instrument failures are named as such, controls beside them | STEP 1.1 |
| A mandated tool unavailable mid-run, improvised silently | Vendor-down fallback named at plan time; deviations reported as deviations | Already true |
| A create reported success that never landed | Every write read back through a separate query before dependence | STEPS 4, 12–14 |
| Three wiring gaps invisible to every automated layer | The feature is opened by the real click path before "working" | STEPS 10–11 |
| A cache-busted asset edited without its version bump | The reuse kit's kill-list carries the ?v= rule; frame CSS changes verified on the registered client | STEP 15, U13 |
| A deliberate default mistaken for a bug across identities | Parity claims tested from both identities where claimed | §1 HOW IT'S USED |
| An update surface wired to a store the reader can't see | Read-path-a-person-uses is each live leg's proof | STEPS 12–14 |
| A work-type gate refused an oversight brief twice | Dispatch headers follow §T verbatim; oversight briefs open with their role line | §5 |
| A brief refused for the missing travel block | The header template with pasted substance is in every brief | §5 |
| A tool died mid-task leaving untested-but-valid state | Partially-applied work is proven by the next holder, never resumed as done | STEP 2 |
| A fresh-context pass was the only thing that caught it | STEP 2 is a genuinely fresh session; STEP 16 is blind | STEPS 2, 16 |
| A data fix applied to one of two live copies | N/A: no dual-copy data store is touched — the desktop loads the deployed site, one origin | §1 |
| A regression suite silently crashing for a day | Harnesses re-run first-hand with exit codes read, not remembered | STEPS 12–14 |
| Load-bearing work never committed | Scoped commit at every step boundary is in every fence | §3 |
| "More detail" answered by polishing instead of gathering | This plan was built by opening sources (registry, spec, handoffs, disk), not elaborating | §0 |
| A gate covering some tool surfaces but not others | N/A: no access-control gate is built here; security pass is click-gated later | anti-scope |
| A default parameter making a branch unreachable | Voice failure branches forced live (interruption, provider failure) | STEP 3.3 |
| Atomic-write on a multi-writer file losing appends | Evidence files are single-writer; registry append is paired and scoped | §3, STEP 17 |
| A red-proof claimed but never run | The sweep's red run is recorded, both directions | STEP 9 |
| Tests writing into the real production log | Live-send tests stay inside the standing scopes; bare runs proven safe first | STEPS 12–14 |
| Trust re-derived from a persisted file | Ephemeral voice tokens live in memory for one session only | STEP 3 |
| A fire-and-forget promise able to crash the daemon | N/A: no daemon code is written here; a found instance goes to NEXT | anti-scope |
| A supersession dropping an unowned piece | The supersession keeps the FINISH LINE derived from Nick's asks, not the old plans' shape | header, §1 |
| fs.watch assumed sufficient under real load | N/A: no filesystem-event mechanism is built here | — |
| A plan asserting repo facts it never checked | Every symbol/path in this plan was grep/glob-verified 2026-09-04 | §0 |
| Fixing what was broken instead of what was asked | REPLACING/RETIRING list marks the dictation flow do-not-invest | §1 |
| A well-formed plan that couldn't deliver the ask | The FINISH LINE is his sentences; STEP 3's proof fails while his complaint stays true | FINISH LINE |
| An agent's self-account taken as root cause | Self-descriptions are V2 claims; implementations get opened | STEP 2 |
| Three verifications with the wrong scope | Proofs name the surface observed (installed app, live URL, running process) | step proofs |
| An orchestrator's confident relay outran the plan | Verdicts relayed unchanged; builders hold standing to refuse with evidence | STEP 16 |
| A handoff read as a gate serializing free work | Entry conditions name PREREQUISITE facts; six steps enter on "nothing" | §3b |
| Approval machinery failing silently | Sheet rows default-and-continue; nothing stalls on an unanswered row | §1a |
| A governance CLI silently dropping flags | N/A: no governance tooling is built here | — |
| Plans degenerating into session logs | Banned shapes honored; history goes to the postmortem, statuses edited in place | STEPS |
| A six-word punchlist item pointing at the wrong action | Every step carries literal actions and the failure that would refute it | §3b |
| A secret reading as SET while its value was empty | Flag/key presence read from the running process, presence-and-length only | STEP 4 |
| The same claim confirmed by a verifier, refuted by an adversary | STEP 2 attacks (response.create refusal); STEP 16 is blind, not confirming | STEPS 2, 16 |
| Reasoning about a system instead of asking it | Ask-the-system moves throughout (read-backs, process reads, live drives) | step proofs |
| A prerequisite discovered after a ruling, unowned | Every dependency found mid-drive gets an owner in the same edit | trip-over |
| A relay acted on or refused with no risk test | Bar-raising relays act now; permission-granting waits for Nick's words | §5 |
| Two programs' instruments reporting non-states | Every instrument here must have gone red once (red-proofs, sabotage runs) | STEP 9 |
| A PROOF block passing with template placeholders | No placeholder tokens ship in this plan; proofs carry literal expected output | §3b |
| Destroyed evidence indistinguishable from fabricated | Six evidence states declared; DESCRIBED-NOT-PRESERVED carries its reason | step proofs |
| A capability ruled impossible by a blind query | Negatives name what the query CAN see (Alexa device leg's three attempts) | STEP 14 |
| The four UI instrument lies | STEP 11 asserts app-unique elements, focuses before clicks, isolates failures on untouched controls | STEP 11 |
| An entry gate satisfied while the step can't run | RUNNABLE WHEN lines separate from entry conditions | STEP 1 |
| A proof pipeline's own warning overridden by its status | A tool's own warning field is a verdict; checker reads it | §3b |
| A dispatch gate contradicting its own security line | Contradictions get logged and escalated, never reworded around | §5 |
| The fallback itself blocking the cutover | ElevenLabs rollback and OpenAI path share no exclusive resource — checked at STEP 3 before concluding anything is broken | STEP 3 |
| An approved instruction gone stale before delivery | Sheet answers are re-read against their reason if hours pass before use | §1a |
| EDITED vs DEPLOYED vs REGISTERED collapsed | U13/U10 prove on the registered client and installed app; content-type checked on any fetched negative | §2 |
| Working-tree state read as system state | git blame before calling any behavior pre-existing; in-flight work suspected first | §3 (§W) |
| Three honest proofs, untouched complaint | The user-sentence proof rule binds STEP 3 and STEP 16 | STEPS 3, 16 |
| A local caution escalated into a fleet halt | Halts name what they buy and cost; one agent's hold never broadcasts | §5 |
| An overseer's inbox mistaken for the world | Status claims come from artifacts, never from not-having-heard | §5 |
| An acknowledgement read as the outcome | Every enqueue pairs with its dequeue/read-back; `queued` is needs_review | STEPS 12–14 |
| Authority bridged from a different ruling | Every authorization here quotes the exact question Nick answered, dated | §1a |
| An agent asking to loosen a guard to unblock a test | Hard line restated: never ask; prove no authorized instrument exists first | STEP 14 |
| A self-healing fault invisible to every alarm | Live legs read event logs over a window, not a sample | STEPS 12–14 |
| A metric's recorded limitation forgotten at use | Each proof names what result would disprove it | §3b |
| An investigation contaminating its own evidence | Origin-classified hits; second method run by a different session | STEP 2 |
| Point-in-time probes missing intermittent faults | Window-over-period rule honored where flapping is possible (voice, channels) | STEPS 3, 12–14 |
| An overseer relaying genuine words as authority | Standing orders carry Nick's tap; relays carry facts only | §5 |
| A self-documenting file lying to unanchored greps | Greps anchor on declarations (`^const`, exact literals), never version-shaped prose | step proofs |
| A cited hash unreachable or unpushed later | Cited commits carry messages; reachability re-proven at citation time | §W rules, §3 |
| A proof command over-matching a sibling table | Counts near-but-not-equal trigger a scope check before reporting | §3b |
| A deliberate commit pre-empted by an auto-snapshot | Edits and their scoped commit in one invocation; shared dependency widened last | STEP 17, §3 |
| A test reaching a live send path while claiming safety | Bare-run safety proven first (measured exit 0 without the live flag); live legs only inside standing scopes | STEPS 12–14 |
| A denominator changed mid-drive to keep a build open | The 18-row manifest is pinned at planning time; no rows added mid-drive | STEP 16 |
## 5 · Topology and roles
- **OVERSEER-AUTHORITY:** none named for this drive in `projects/ops/OVERSEER-AUTHORITY.md`'s CURRENT HOLDER table at write time — this plan's lanes work under the drive's own Fable overseer per Nick's 2026-09-04 mandate; the four approval classes and the data floor never move on any overseer's word.
- Thread layout: ONE overseer thread (Fable). Worker sessions per lane, dispatched as needed, never idle-waiting.
- Overseer: fable (build work + design QA oversight; never builds, never swarms one finding — a finding gets ONE owner or the NEXT list) · Lane managers: none needed at this size — the overseer coordinates directly · Workers: glm builders, sonnet checkers/drivers, Sienna (fable) for design QA.
- State files location: `projects/ops/skippy-master-plan/` — STATE-SKIPPY-FINISH.md, PLAN-CHANGES-SKIPPY-FINISH.md (both beside this plan).
- **Board card id:** none yet
- **Artefact consumers:** step evidence → STEP 16's blind checker; DONE + layer lines → STEP 16 and the wider Skippy test manifest; the reuse kit → the Hub plan's owner and the family-app plan's owner (handoff line posted into each when STEP 15 closes); the postmortem → the failure registry and Nick.
- **Write-contention:** per-lane fences in §3; the checkout is proven writable at STEP 1 (probe write + read-back); the only shared-file sequencing is signal-frame-window.css between STEPS 6 and 7's wide-cap edit — sequenced, never same-hour. Scoped commits only; skippy-code commits happen inside its own nested repo.
- **Concurrency:** hard ceiling 8 simultaneously-running agents in this session, machine-wide budget ~40 shared across live sessions — count live sessions before the first wave and divide; a wave that has not returned is load, not progress. Raising either number is Nick's call.
**Per-stage topology — counts DECLARED at plan time:**
| Stage | Overseer | Sub-overseers | Workers |
|---|---|---|---|
| Baseline + voice (STEPS 1–4) | 1 | 0 | 3 |
| Reskin (STEPS 5–9) | 1 | 0 | 4 |
| QA + desktop (STEPS 10–11) | 1 | 0 | 2 |
| Channels (STEPS 12–14) | 1 | 0 | 3 |
| Kit + close (STEPS 15–17) | 1 | 0 | 2 |
**The walk-away contract — a stranger resumes the drive from files alone:**
- **STATE FILE:** `projects/ops/skippy-master-plan/STATE-SKIPPY-FINISH.md` (created by the drive at STEP 1, current-state-only, rewritten in place)
- **HEARTBEAT ROW:** skippy-finish-drive, registered by the drive coordinator in projects/personal/skippy-app/ala-state/work-threads.json when the drive opens
- **MORNING-REPORT LINE:** "Skippy finish — <n>/18 manifest rows verified, current step, next unblocked step" in projects/ops/walkaway/REPORT.md
## 6 · Evals — what "working" means, decided now
| Capability | Check (exact command or procedure) | Pass looks like |
|---|---|---|
| Hands-free spoken conversation via OpenAI path | STEP 3's live drive on the real Mac, flags ON | one full spoken round trip; interruption + failure recover honestly; Nick's sentence ("we chat back and forth without clicking buttons") true |
| Shape 2 invariant holds | STEP 2.3's attack: send `response.create` to the transcription session | refused by name, never silence |
| Deep Mint everywhere, exactly | `node projects/personal/skippy-app/design-directions/_deep-mint-sweep.mjs` (CREATED BY STEP 9) | exit 0, full grid line, `#ABCFAC`/`#F0E8DA` sampled exact, forbidden list zero |
| Dark mode does nothing | sweep's dark-forced captures diffed against light | pixel-identical |
| Installed app honest states | STEP 11's behavior drive | four states proven by screenshot + behavior |
| Slack works, done | `node projects/personal/skippy-app/channels/_test-smp6-secure-boundary.mjs` + live round-trip | exit 0 + destination read-back |
| Gmail works, done | `node projects/personal/skippy-app/channels/_test-smp6-gmail-draft-only.mjs` + live draft leg | exit 0 + draft read back from mailbox |
| WhatsApp works, done | `node projects/personal/skippy-app/wa/_test-smp7-secure-boundary.mjs` + live send | exit 0 + destination read-back |
| Alexa works, done | `node projects/personal/skippy-app/alexa/test-adapter.mjs` + simulator + live leg | exit 0 + typed outcome or honest NOT AGENT-TESTABLE with one ask |
| Reuse kit usable cold | STEP 15's cold-reader dry run | zero questions filed |
| The plan itself stays valid | `python3 projects/ops/agents/check_plan.py projects/ops/skippy-master-plan/PLAN-SKIPPY-FINISH.md` from the repo root | exit 0 |
## If you get stuck (all steps)
Before writing "blocked": (1) try a concrete workaround, (2) re-read the step's proof requirements — most "stuck" is a misread gate, (3) write one line to the overseer AND the owner of the blocker. Only then log `STEP <N> BLOCKED — tried: <a>,<b>,<c>. Need: <one sentence>.` Then keep working every other unblocked step. Never idle on a blocker; never end a turn waiting on a background result. The only justified stops: the four approval classes · the data floor · the ZION-8 security click · a proof that would destroy live data.
## Your loop
Every pass: find the lowest-numbered step whose entry condition is proven and which is not yet proven → do it → produce its proof → paste the proof under the matching item in STEPS below → repeat. Six steps enter on "nothing" — the queue is never empty until the FINISH LINE.
## SUMMARY — a few plain-English lines, read by the status generator
The plan to finish Skippy is written and nothing has been built against it yet. What's already real: the voice upgrade is mostly wired but switched off, the new look is fully specified with the approved mockup found, and all four messaging channels are built with their self-tests passing. What remains: switch the voice on and prove a real spoken conversation, dress every screen in the approved look, test the four channels live and call them done, and write down the recipe so the Hub and family app get the same treatment next.
## STEPS
1. Live baseline + topology pin — 0%
DEFINITION OF DONE: honest defect list + serving topology recorded with artifacts
PROOF: `ls projects/ops/skippy-master-plan/evidence` shows the smp-finish-01 baseline + screenshots
2. Independent verification of the voice listening half + wiring — 0%
DEFINITION OF DONE: per-check verdict file, Shape 2 attack shown
PROOF: `node --check projects/personal/skippy-app/skippy-code/lib/openai-realtime-adapter.mjs`
3. [UI] End-to-end real-mic conversation, flags ON in test — 0%
DEFINITION OF DONE: one full spoken round trip + interruption + failure-recovery, artifacts saved
PROOF: `command grep -c "voiceOriginated" projects/personal/skippy-app/skippy-code/server.js`
4. Voice go-live, rollback intact — 0%
DEFINITION OF DONE: flags default ON, read back from the running process, ElevenLabs branch present
PROOF: `command grep -ci "elevenlabs" projects/personal/skippy-app/skippy-code/server.js`
5. Reskin groundwork: fonts loaded, mono/dark blocks deleted — 0%
DEFINITION OF DONE: kill-greps print 0, computed font resolves to the loaded face
PROOF: `command grep -c 'font-family: var(--mono) !important' projects/personal/family-app/css/signal-frame-window.css`
6. [UI] S1–S4 Deep Mint restyle — 0%
DEFINITION OF DONE: tokens exact, forbidden list zero, 27 ids untouched
PROOF: `command grep -c '#ABCFAC' projects/personal/family-app/css/signal-frame-window.css`
7. [UI] S5 widget + S6 collapsed + native window ground — 0%
DEFINITION OF DONE: Part 5 conformance table closed; main.js dark hex gone (2 hits today)
PROOF: `command grep -c '#07080a' projects/personal/skippy-app/desktop/main.js`
8. [UI] Signal shell wears Deep Mint (NO-OP only on evidence + overseer sign-off + a line to Nick) — 0%
DEFINITION OF DONE: shell tokens match (count 0 today), element-id-set diff empty
PROOF: `command grep -c '#ABCFAC' projects/personal/skippy-app/skippy-code/public/index.html`
9. Visual sweep harness + full-grid capture — 0%
DEFINITION OF DONE: harness exits 0 with the full grid line and a recorded red-proof
PROOF: `ls projects/personal/skippy-app/design-directions`
10. [UI] Sienna's six-check design QA, one round — 0%
DEFINITION OF DONE: verdict file, evidence per check, one fix pass max
PROOF: `node projects/personal/skippy-app/design-directions/_deep-mint-sweep.mjs` (CREATED BY STEP 9)
11. [UI] Installed-app honest states drive — 0%
DEFINITION OF DONE: launch/offline/error/recovered proven by behavior on the installed app
PROOF: `node --check projects/personal/skippy-app/desktop/main.js`
12. Slack + Gmail testing phase — 0%
DEFINITION OF DONE: harnesses green first-hand + live round-trips read back from the destination; DONE + layer lines written
PROOF: `node projects/personal/skippy-app/channels/_test-smp6-secure-boundary.mjs`
13. WhatsApp testing phase — 0%
DEFINITION OF DONE: harnesses green first-hand + live send read back; DONE + layer lines written
PROOF: `node projects/personal/skippy-app/wa/_test-smp7-secure-boundary.mjs`
14. Alexa testing phase — 0%
DEFINITION OF DONE: suite + simulator green first-hand; live leg's evidence state declared honestly
PROOF: `node projects/personal/skippy-app/alexa/test-adapter.mjs`
15. Reuse kit for Hub + family app — 0%
DEFINITION OF DONE: cold reader applies it dry-run with zero questions
PROOF: `ls projects/personal/skippy-app/design-directions`
16. Blind final QA — all 18 rows re-run, DONE = 18/18 pass — 0%
DEFINITION OF DONE: fresh blind checker graded all 18 manifest rows; verdict relayed unchanged; shortfall reported as NOT DONE
PROOF: `python3 projects/ops/agents/check_plan.py projects/ops/skippy-master-plan/PLAN-SKIPPY-FINISH.md`
17. Postmortem + NEXT list + close — 0%
DEFINITION OF DONE: postmortem written into this plan; registry append paired with its covering row
PROOF: `command grep -c "POSTMORTEM" projects/ops/skippy-master-plan/PLAN-SKIPPY-FINISH.md`
# STATE — Finish the Skippy app and its voice app · created 2026-09-04 ## Current state (rewritten in place — this section only, never appended) **Plan written and cold-reviewed; lane not yet open.** No step has run. The plan is `PLAN-SKIPPY-FINISH.md` beside this file. It has been through two independent adversarial reads. The first, run by its own author before finishing, returned seven disputes — including three step proofs that would have passed with zero work done — and all seven were corrected. The second, a cold cross-plan review on 2026-09-04 that read this plan alongside the Hub and retirement plans, re-checked those seven fixes against the files rather than trusting the report and confirmed every one genuinely landed. It returned this plan READY with no internal blockers. **The one change that review made here:** STEP 15's reuse kit now owns the VOICE setup, not only the visual one. The Hub plan was waiting on a reusable voice pattern that no plan produced, and the ruling put it in this lane on Nick's own words — *"finish voice app then we deploy the same etup in the hub and family app"* (2026-09-04). The voice setup is built once, here, and handed over. STEP 15's close now posts a dated handoff line into `projects/ops/zion/STATE-ZION-19.md` §HANDOFFS-IN, and that line is what releases the Hub's queued step. ## Ground truth measured at planning time (re-measure before acting) - The visual reskin is already PARTLY LANDED on disk. This is why three of the original step proofs could have passed with no work done, and why those steps are now written as spec-conformance passes whose proofs fail against today's files. - Retired colours still live in the desktop shell's own entry file, which every lane had fenced OFF — that line now has an explicit owner, or the dark-mode finish-line item is unreachable. - The font is only partly on disk (one weight, outside the served tree), so the fence was opened for weight files. - The listening half carries an independent verification from 2026-09-03 which found a real deadlock bug whose fix was never re-verified, and which warns the verified function may not be the code that ships. STEP 2 is retargeted at exactly those two open ends. - Slack, Gmail, WhatsApp and Alexa are BUILT — confirmed on disk. They need a testing phase to confirm they are ready, then they are done for Skippy and become layers other tests run against. They are not rebuilt. ## Handoffs owed by this lane | To | What | When | |---|---|---| | `projects/ops/zion/STATE-ZION-19.md` §HANDOFFS-IN | One dated line naming the reuse kit's path and the specific voice files the Hub is to port | At STEP 15's close | ## Who is driving this - **Overseer session:** the Skippy-finish Fable overseer thread (topology in the plan's §5). - **Lanes re-read this file:** at the start of every step. - **Unowned-blocker owner:** the overseer. ## Questions (open → answered, in place) - Two preference questions ride the plan's own confirmation sheet rather than blocking: whether voice switches on the moment it passes or shows Nick first, and the font default. ## Contract-change log - 2026-09-04 — STEP 15 widened from design-only to design + voice, per the cross-plan cold review's ruling. Recorded in `PLAN-CHANGES-SKIPPY-FINISH.md`.