--- phase: 07-hardening-private-launch plan: 06 type: execute wave: 3 depends_on: - "07-01" - "07-02" - "07-03" - "07-04" - "07-05" files_modified: - .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md - .planning/STATE.md autonomous: false requirements: - PX-04 must_haves: truths: - "One consolidated walk covers Android, iOS, Telegram Desktop and a plain browser across seven interactions, and every leg carries a recorded PASS/FAIL/NOT RUN verdict — never a synthesized one." - "The battery result is a RECORDED real measurement from one Android guidance run of at least 30 screen-on minutes — never extrapolated, never synthesized." - "The launch checklist is signed only when every automated gate is green, the known-limitations doc is shipped, the privacy audit is signed, and the budget record is green." - "The launch act itself is the user's — the workflow produces the evidence and the checklist, never the distribution." artifacts: - path: ".planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md" provides: "The signed launch gate — the device matrix, the battery record, and the D-09 checklist" contains: "FINAL VERDICT" - path: ".planning/STATE.md" provides: "The milestone completion record (D-09 — the milestone completes when the checklist is signed)" contains: "milestone" key_links: - from: ".planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md" to: ".planning/phases/07-hardening-private-launch/07-03-PLAN.md" via: "the checklist's privacy-audit line references the signed record in docs/PRIVACY-AUDIT.md" pattern: "PRIVACY-AUDIT" - from: ".planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md" to: "docs/KNOWN-LIMITATIONS.md" via: "the checklist's known-limitations line names the shipped doc" pattern: "KNOWN-LIMITATIONS" --- Close the phase honestly: one consolidated device-matrix walk, one recorded Android battery run, the D-09 launch checklist — and the milestone's completion record. Purpose: D-05 — the QA pass is ONE walk (four clients × seven interactions), not four separate sessions. D-04 — the battery target is a RECORDED real measurement, never synthesized. D-09 — the private launch IS the checklist being signed; the launch act itself is the user's. This plan produces the gate FILE (the protocol + the record) and then blocks for the human. Output: `.planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` (new — the protocol, the empty result tables, and the signature block) and, after the human signs, the `.planning/STATE.md` milestone completion record. @$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md @$HOME/.config/opencode/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/07-hardening-private-launch/07-CONTEXT.md @.planning/phases/07-hardening-private-launch/07-RESEARCH.md @.planning/phases/07-hardening-private-launch/07-PATTERNS.md The gate-file structure to copy — `.planning/phases/06-turn-by-turn-guidance-live-driving/06-DEVICE-GATE.md` (its blocking header at lines 3–8, its part tables at lines 32–43, its executor notes at lines 59–68, and its FINAL VERDICT section at lines 72–82): ```markdown **Status: BLOCKING — awaiting the human.** Everything automatable is green: … Per the plan's law: **device results are never faked** — this file records the protocol; the SUMMARY records the verdict verbatim once the drive runs. A FAIL holds the phase open. | # | Step | Verify | |---|------|--------| ## Executor notes for the run - **Never fake**: if a step cannot be executed (weather, road, time), mark it NOT RUN — do not invent an outcome. The phase stays open on any FAIL or NOT RUN. ## FINAL VERDICT | Part | Verdict | |------|---------| ``` The battery record fields (from 07-RESEARCH.md §Pitfall 11 and D-04): | Field | Requirement | |-------|-------------| | Device / model | required | | OS + Telegram client version | required | | Screen brightness | required | | Network (Wi-Fi / cellular) | required | | Screen-on interval | ≥ 30 minutes | | Battery % at start | required | | Battery % at end | required | | Route / drive description | required | | Elapsed minutes | required | | Computed %/hr | (end − start) / (elapsed minutes / 60) | | Caveats | required (background apps, signal loss, other load) | The seven interactions (D-05) — each leg is tested against every client: 1. boot 2. search → route 3. guidance 4. minimize / resume 5. trip-end 6. theme flip 7. landscape / fullscreen The D-09 launch checklist (six items): - known-limitations shipped - privacy audit signed - budget record green - full device matrix walked - `/help` + `/privacy` accurate - repo pushed public under GPL-3.0 task 1: write the launch gate file (the protocol, the empty result tables, the checklist, the signature block) .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md - .planning/phases/06-turn-by-turn-guidance-live-driving/06-DEVICE-GATE.md (the WHOLE file is the structural template) - .planning/phases/03-mini-app-shell-geolocation/03-DEVICE-MATRIX.md (the six-leg table + the FINAL VERDICT table shape) - .planning/phases/07-hardening-private-launch/07-CONTEXT.md (D-04, D-05, D-09 verbatim) - .planning/phases/07-hardening-private-launch/07-RESEARCH.md §Pitfalls 11 and 12 Create `.planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` (NEW — the whole file is new), copying `06-DEVICE-GATE.md`'s structure exactly. It MUST contain, in this order: **1. A blocking status header.** Name what is already green at the time of writing — the suite counts and the exact commands (`npm run bot:test`, `npm run web:test`, `npm run routing:test`, `npm run search:test`, `npm run privacy-audit`, `npm run budget-audit`, `npm run capture -w web`) — and include the never-fake law VERBATIM in the file's own voice: "device results are never faked — this file records the protocol; the SUMMARY records the verdict verbatim once the walk runs. A FAIL holds the phase open." **2. `## Part A — the consolidated device-matrix walk (D-05)`.** A FOUR-CLIENT × SEVEN-INTERACTION table. The four clients are: Android (real phone, Telegram Android), iOS (real phone, Telegram iOS), Telegram Desktop, and a plain browser. The seven interactions are: boot · search→route · guidance · minimize/resume · trip-end · theme flip · landscape/fullscreen. The table shape is one row per CLIENT with a per-interaction verdict column set: ```markdown | Client | boot | search→route | guidance | minimize/resume | trip-end | theme flip | landscape/fullscreen | Notes | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Android (real phone, Telegram Android) | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | | | iOS (real phone, Telegram iOS) | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | | | Telegram Desktop | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | | | Plain browser | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | | ``` The verdict vocabulary is `PASS` / `FAIL` / `NOT RUN` — one word per cell, plus the free-text Notes column. Define the vocabulary right above the table: "PASS = the interaction completed as designed on this client · FAIL = it did not (the phase stays open) · NOT RUN = the client or the step was unavailable (NOT RUN is never PASS)." Add a `### What to check per interaction` list — one short line per interaction, stating the observable pass condition: - boot: the app reaches LIVE (or the DESIGNED denied state on a client with no geolocation — the denied state IS the pass condition there, a blank screen is a FAIL). - search→route: a destination resolves to a KL landmark, the route draws, the route card shows time + distance. - guidance: the maneuver banner shows distance + arrow + street; the ETA advances without whiplash; the haptic fires at the maneuver (where the client supports it). - minimize/resume: minimizing the app mid-drive produces a chat turn-card within ~3–4 minutes; re-opening resumes at the progressed position. - trip-end: END TRIP → the confirm card → abandon shows the trip-ended card and the envelope is deleted. - theme flip: the chrome re-slots light↔dark mid-session, the strip stays matte-black, and THE MAP IS UNCHANGED (same style, no flash, no camera jump). - landscape/fullscreen: rotating the device (or the desktop window) keeps the banner, the maneuver list, the guidance card and the map all usable with no overlap and no clipping; on Telegram 8.0+ clients the Mini App enters fullscreen at guidance start, and on older clients it simply stays portrait/landscape-usable (that IS the pass condition there). **3. `## Part B — the Android battery record (D-04)`.** A table with the field list from the interfaces section above, all values left as `⬜` EXCEPT the rows that name a REQUIREMENT (device, OS, client version, brightness, network, screen-on interval ≥ 30 min, start %, end %, route, elapsed minutes, computed %/hr, caveats). Below the table, the honest rule, in the file's voice: "The <10%/hr target is RECORDED, never synthesized. If the run is shorter than 30 screen-on minutes, or it is interrupted, mark the row NOT RUN and keep this gate open. Do not extrapolate a percentage from a shorter run." **4. `## Part C — the automated half (re-run at gate time)`.** A table of the exact commands with a `⬜` result column, so the human can re-run them at gate time and see the counts: `npm run bot:test` · `npm run web:test` · `npm run routing:test` · `npm run search:test` · `npm run search:corpus` · `npm run routing:corpus` · `node routing/scripts/measure-route-cpu.mjs` · `npm run privacy-audit` · `npm run budget-audit` · `npm run capture -w web` · `npm run privacy-audit -- --live` · `npm run budget-audit -- --live`. Note under the table: "A `--live` probe that reports NOT RUN (exit code 2) means the credentials or the environment were absent — that is NOT a pass. The launch checklist stays unsigned until the live probes are green." **5. `## Part D — the D-09 launch checklist`.** Six checkbox rows, each with the evidence that satisfies it: - [ ] Known-limitations shipped — `docs/KNOWN-LIMITATIONS.md` is in the repo and `/help` points at it (en + ms). - [ ] Privacy audit signed — `docs/PRIVACY-AUDIT.md` carries the evidence and a human signature; `npm run privacy-audit` exits 0. - [ ] Budget record green — `docs/BUDGETS.md` is in the repo; `npm run budget-audit` exits 0 and the c3 degradation class is stated honestly. - [ ] Full device matrix walked — Part A has no FAIL and no NOT RUN. - [ ] `/help` and `/privacy` accurate — the replies match the shipped behaviour and the limitations pointer line resolves. - [ ] Repo pushed public under GPL-3.0 — the remote is public, the root `LICENSE` is GPL-3.0, and `docs/ROAD-GRAPH.md` + the audit commands are the fork's onboarding path. **6. `## Executor notes for the run`.** The known-open items: the `/cari` menu defect (type the command — the doc says so); the cross-metro c3 degradation (a long cross-metro trip may land on the router-pending card); the R2 / graph upload state (if the graph is absent, `/api/route` answers honest nulls and long routes degrade); the live-probe credential caveat; and the never-fake rule. **7. `## FINAL VERDICT`.** A part-by-part table (`| Part | Verdict |` with rows A, B, C, D), left EMPTY for the human to fill, followed by a dated signature block: ```markdown --- ## FINAL VERDICT — ⬜ NOT YET SIGNED | Part | Verdict | | --- | --- | | A. The consolidated device matrix | ⬜ | | B. The Android battery record | ⬜ | | C. The automated half | ⬜ | | D. The launch checklist | ⬜ | **Signed:** ______________________ **Date:** ____________ ``` Do NOT fill any verdict in this task — the file records the PROTOCOL. The human fills the verdicts. - `.planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` exists and contains the section headings `## Part A — the consolidated device-matrix walk (D-05)`, `## Part B — the Android battery record (D-04)`, `## Part C — the automated half (re-run at gate time)`, `## Part D — the D-09 launch checklist`, `## Executor notes for the run`, `## FINAL VERDICT` - `grep -c "device results are never faked" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns ≥ 1 - `grep -c "NOT RUN" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns ≥ 3 (the verdict vocabulary, the battery rule, and the executor note) - `grep -c "⬜" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns ≥ 20 (the empty result cells — nothing is pre-filled) - `grep -c "Known-limitations shipped" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns 1 and `grep -c "Repo pushed public under GPL-3.0" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns 1 (the six D-09 checklist items) - `grep -c "SIGNED" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns ≥ 1 and the file contains NO filled verdict (no `APPROVED` string) export PATH="$HOME/.nvm/versions/node/v24.18.0/bin:$PATH"; cd /home/C-Fu/araharah && test -f .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md && grep -c "⬜" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md && ! grep -q "APPROVED" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md && echo "gate file is an empty protocol" The launch gate file exists with the full protocol — the 4×7 device matrix, the battery record fields, the automated-half commands, the six D-09 checklist items, and an unsigned FINAL VERDICT block. task 2: THE CONSOLIDATED WALK + THE BATTERY RUN (the blocking human gate) .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md - .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md (the protocol written in task 1 — the verdict vocabulary, the per-interaction pass conditions, the battery field list, and the six checklist items) - .planning/phases/06-turn-by-turn-guidance-live-driving/06-DEVICE-GATE.md (the never-fake protocol precedent) The human walks the four clients, runs the battery measurement, and fills the verdict tables IN PLACE in `07-LAUNCH-GATE.md`. No automated step replaces any of it. - `grep -c "⬜" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns 0 (every verdict cell is filled — no cell is left blank) - `grep -c "NOT YET SIGNED" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns 0 (the FINAL VERDICT header was updated to the signed verdict) - `grep -c "Signed:" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns 1 and the signature line is NOT blank (a name is written) - `grep -c "Date:" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns ≥ 1 and the date line is NOT blank - `grep -c "FAIL" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` returns 0 in the FINAL VERDICT table OR the gate is reported as NOT SIGNED (a FAIL keeps the phase open — the file must not claim a signed state with a failing part) - the Part B table contains a start %, an end %, and an elapsed-minutes value (the battery record is measured, not blank) Everything automatable in Phase 7: the fullscreen capability layer and its 8.0 fallback (07-01), the landscape cockpit geometry and the failure-state matrix (07-02), the consolidated privacy audit and its signed record (07-03), the consolidated budget record and the static-asset cache policy (07-04), and the paid debts plus the known-limitations document (07-05). The launch gate file (07-06 task 1) holds the empty protocol: a 4×7 device matrix, the battery record fields, the automated-half command list, and the six D-09 checklist items. What is left is exactly what no tool can produce: the physical walk and the measured battery number. **Part 0 — the automated half (re-run at gate time, ~2 minutes).** From the repo root: ``` npm run bot:test && npm run web:test && npm run routing:test && npm run search:test npm run search:corpus && npm run routing:corpus node routing/scripts/measure-route-cpu.mjs npm run privacy-audit npm run budget-audit npm run capture -w web npm run privacy-audit -- --live npm run budget-audit -- --live ``` Every command must exit 0. A `--live` probe that prints `NOT RUN` and exits 2 is NOT a pass — the credentials must be present. **Part A — the ONE consolidated walk (D-05).** Open the deployed Mini App from the bot on each of the four clients, and work through all seven interactions on EACH client: boot · search→route · guidance · minimize/resume · trip-end · theme flip · landscape/fullscreen. Fill one verdict word per cell in Part A of `.planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md` — PASS, FAIL, or NOT RUN — plus a note in the Notes column. The pass conditions are listed in the file under "What to check per interaction"; read them before starting. A NOT RUN cell (a device that was not available) keeps the checklist unsigned — it is not a PASS. **Part B — the battery run (D-04).** On the Android phone, start a guidance run and keep the screen on for AT LEAST 30 MINUTES of real driving (a real route, not a stationary app). Read the battery percentage immediately before starting and immediately after ending, and fill every field of Part B: device, OS, Telegram client version, brightness, network, the screen-on interval, start %, end %, the route, the elapsed minutes, the computed %/hr, and the caveats. If the run was shorter than 30 minutes or was interrupted, mark it NOT RUN and leave the gate open — do not extrapolate. **Part C — the automated half table.** Fill the result column for each command. **Part D — the checklist.** Tick each of the six items only when its evidence actually exists: the limitations doc is in the repo and `/help` points at it; `docs/PRIVACY-AUDIT.md` is signed; `docs/BUDGETS.md` is green and states the c3 class; Part A has no FAIL and no NOT RUN; `/help` and `/privacy` read accurately against the shipped behaviour; and the remote repository is public with the root `LICENSE` at GPL-3.0. **The verdict.** Fill the FINAL VERDICT table (Parts A–D) and the signature line with your name and the date. **The launch itself is yours.** Once the checklist is signed, the milestone completes — the workflow does NOT distribute the bot link. Give it to your first KL drivers yourself. Type "signed" with the FINAL VERDICT filled (and paste the Part A matrix and the Part B battery numbers), or describe what failed / which legs were NOT RUN. On "signed", the executor writes the milestone completion record into `.planning/STATE.md`. On a FAIL or a NOT RUN, the phase stays open — open a `/gsd-debug` for the failing symptom and record the NOT RUN legs honestly. export PATH="$HOME/.nvm/versions/node/v24.18.0/bin:$PATH"; cd /home/C-Fu/araharah && grep -c "SIGNED" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md && ! grep -q "⬜ NOT YET SIGNED" .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md && echo "the gate file is signed (the NOT YET SIGNED marker is gone)" Every Part A cell carries a PASS/FAIL/NOT RUN verdict with a note; Part B carries a real ≥30-minute Android battery measurement (or an explicit NOT RUN); Part C's command table is filled; Part D's six checklist items are each backed by their named evidence; and the FINAL VERDICT table is signed with a name and a date. task 3: record the milestone completion in STATE.md (after the checklist is signed) .planning/STATE.md - .planning/STATE.md (the whole file — the frontmatter fields, the "Current Position" block, the "Accumulated Context" sections, and the "Progress" table) - .planning/phases/07-hardening-private-launch/07-LAUNCH-GATE.md (the signed FINAL VERDICT — the source of this record) - .planning/ROADMAP.md (the Phase 7 entry — update its "Plans" count and its plan list) ONLY run this task after the checkpoint returned "signed" and the gate file's FINAL VERDICT table is filled. In `.planning/STATE.md`: 1. Update the frontmatter `status:` to `complete` and `stopped_at:` to a sentence naming the signed launch gate (e.g. `Phase 7 complete — the launch gate is signed (private beta checklist)`). Update `last_updated:` and `last_activity:` to today's date. 2. Update the `## Current Position` block: `Phase: 7` → `Phase: 7 (complete)`, `Plan: Not started` → `Plan: Complete`, `Status: Ready to plan` → `Status: Launch gate signed`. 3. Set the `Progress:` bar to `[░░░░░░░░░░] 100%`. 4. In `## Accumulated Context` → `### Decisions`, ADD a bullet recording the Phase-7 decisions that bind future work: - The private launch is a checklist-signed private beta; the launch act is the maintainer's. - v1 carries ZERO telemetry — the audit proves an absence; opt-in telemetry is a post-validation milestone. - The cross-metro CPU class (c3) is the standing degradation: cross-metro routes land on the router-pending card; the ALT landmark preprocessing is the committed next-milestone lever. 5. In `### Blockers/Concerns`, move the resolved entries into a short "RESOLVED 2026-10-25" note and REMOVE the stale open ones — in particular the `/cari` menu entry stays listed as a KNOWN Telegram-side defect (with the workaround), and the Phase-4 "legs UNVERIFIED" entry is replaced by the Phase-7 walk's recorded verdicts. 6. In `### Deferred Items`, ADD the rows that Phase 7 committed to the v1.x milestone: ALT landmark preprocessing (c2), the WASM-router track, engine B (the fully client-side webview router), and opt-in telemetry — each with "Deferred to v1.x milestone" and "Deferred At: Phase 7 (2026-10-25)". 7. Update `## Session Continuity` — `Last session:` and `Stopped at:` and `Resume file:` (point at the gate file, since it holds the signed record). In `.planning/ROADMAP.md`: 1. Mark the Phase 7 entry `- [ ]` → `- [x]` and add `(completed 2026-10-25)`. 2. The Phase 7 entry already carries `**Plans**: 6 plans` — LEAVE that count line as it is; do NOT replace it and do NOT introduce a `TBD` placeholder. 3. The six Phase 7 plan entries and their one-line objectives already exist in the ROADMAP's plan list — mark each of the six `[x]` (they are done once this task runs). Do NOT add a seventh entry and do NOT reword the six objectives. 4. Update the `## Progress` table's Phase 7 row to `6/6 | Complete | 2026-10-25`. 5. Leave every other phase's rows untouched. Do NOT rewrite the roadmap's success criteria, the goal, or any earlier phase's text. - `.planning/STATE.md` frontmatter contains `status: complete` - `.planning/STATE.md` contains the literal `ZERO telemetry` in the Decisions list - `.planning/STATE.md` contains the literal `ALT landmark preprocessing` in the Deferred Items table - `.planning/ROADMAP.md` contains `**Plans**: 6 plans` under Phase 7 and the phase line contains `- [x] **Phase 7:` - `.planning/ROADMAP.md`'s Phase 7 progress row contains `6/6` export PATH="$HOME/.nvm/versions/node/v24.18.0/bin:$PATH"; cd /home/C-Fu/araharah && grep -c "status: complete" .planning/STATE.md && grep -c "\*\*Plans\*\*: 6 plans" .planning/ROADMAP.md && grep -c "6/6" .planning/ROADMAP.md STATE.md records the completed milestone with the binding decisions and the v1.x deferrals, and ROADMAP.md shows Phase 7 complete with its six plans. ## Trust Boundaries | Boundary | Description | |----------|-------------| | The human report → the milestone record | The launch gate's verdicts are human-supplied observations; they are the only evidence source for the physical properties. | | The signed checklist → the public launch | Signing asserts the artifact set is honest and complete; a false signature is the worst failure mode in the phase. | ## STRIDE Threat Register | Threat ID | Category | Component | Disposition | Mitigation Plan | |-----------|----------|-----------|-------------|-----------------| | T-07-27 | Repudiation | `07-LAUNCH-GATE.md` — a synthesized device verdict or battery number | mitigate | Every cell starts as `⬜`; the vocabulary is PASS/FAIL/NOT RUN with NOT RUN explicitly never counting as PASS; the never-fake law is stated verbatim in the file; the battery rule forbids extrapolating a shorter run; the task's own acceptance criteria assert the file contains NO pre-filled verdict (`APPROVED` absent). A synthesized result is structurally impossible to write by accident. | | T-07-28 | Tampering | the checklist — signing before the evidence exists | mitigate | The six D-09 items each name their own evidence (the shipped doc, the signed audit record, the budget record, a matrix with no FAIL/NOT RUN, the accurate `/help` and `/privacy` replies, the public GPL-3.0 remote). The `--live` probes reporting `NOT RUN` (exit 2) explicitly keep the checklist unsigned. | | T-07-29 | Information Disclosure | `07-LAUNCH-GATE.md` — a device/OS/battery record leaking into a public repo | accept | The gate file records a device model, an OS version, a battery percentage and a route description — no identity, no account, no coordinate, no credential. The repo is published public under GPL-3.0 by design (D-09), and this data class is intentionally disclosed for the battery method's reproducibility. | | T-07-30 | Elevation of Privilege | the milestone completion — the workflow acting as the launch act | mitigate | Task 3 runs only after the checkpoint returns "signed"; the gate file states that the launch act itself is the maintainer's — the workflow produces the evidence and the checklist, never the distribution. STATE.md records the SIGNED checklist, not a distribution. | Run after all tasks: ```bash export PATH="$HOME/.nvm/versions/node/v24.18.0/bin:$PATH" cd /home/C-Fu/araharah npm run bot:test && npm run web:test && npm run routing:test && npm run search:test npm run privacy-audit && npm run budget-audit ``` All must exit 0. The gate file's FINAL VERDICT must be filled and signed, and `.planning/STATE.md` must read `status: complete`. - `07-LAUNCH-GATE.md` exists as a complete, unsigned protocol: a 4×7 device matrix, the battery record fields, the automated-half command list, the six D-09 checklist items, the executor notes, and an empty FINAL VERDICT. - The blocking checkpoint was walked by the human; every matrix cell carries a PASS/FAIL/NOT RUN verdict and the battery run is a recorded ≥30-minute real measurement. - The six checklist items are each backed by their named evidence, and the FINAL VERDICT is signed with a name and a date. - `STATE.md` records the milestone completion with the binding decisions and the v1.x deferrals; `ROADMAP.md` shows Phase 7 complete with six plans. After completion, create `.planning/phases/07-hardening-private-launch/07-06-SUMMARY.md`