<!-- source: openspec/changes/migrate-canvas-realtime-to-broadcast/verification.md -->

---
audience:
  - executor
---
# Verification — migrate-canvas-realtime-to-broadcast

> Companion to proposal.md / design.md / tasks.md.

## Spec alignment

"Done" means all six HOT-tier canvas tables (`canvas_messages`,
`canvas_files`, `canvas_project_instructions`, `canvas_invitees`,
`canvas_sessions`, `research_runs`) deliver Realtime events via
`broadcast_changes`; the bridge subscribes per-table-per-canvas;
`visibilitychange → 'visible'` refetches all six topics; conformance
test asserts p95 ≤ 2s and p99 ≤ 5s across all six. P7b shipped only
after seven consecutive days of P7a soak meeting the SLO.

## Hallucination risks

MUST appear:

- `openspec/changes/migrate-canvas-realtime-to-broadcast/proposal.md` — new.
- `openspec/changes/migrate-canvas-realtime-to-broadcast/design.md` — new.
- `openspec/changes/migrate-canvas-realtime-to-broadcast/tasks.md` — new.
- `openspec/changes/migrate-canvas-realtime-to-broadcast/verification.md` — new.

MUST NOT appear in the scaffold PR:

- No new migration SQL files — Wave 2 + 8 land post-ratification.
- No edits to `packages/state/src/actors/supabase-realtime-bridge.ts` — Wave 3 + 9 land post-ratification.
- No new conformance test — Wave 4 + 10 land post-ratification.
- No edits to `openspec/current/*.md` — Wave 13 amends specs at archive.
- P7b waves (8-12) MUST NOT ship until the P7a soak gate (Wave 7) is satisfied.

## Pattern references

- `openspec/archive/2026-05-20-add-chat-turn-queue/` — sibling P2 change in the same epic; migration + bridge pattern.
- `openspec/archive/2026-05-21-add-chat-e2e/` — sibling P6 change; provides the synthetic monitor whose `bridge_latency_p95_ms` metric the soak gate reads.
- `packages/state/src/actors/supabase-realtime-bridge.ts` — existing bridge; this change adds the broadcast path conditionally.
- `supabase/migrations/` — existing migration conventions to mirror.

## Acceptance

### Wave 1 — Scaffold

- Done when: file `openspec/changes/migrate-canvas-realtime-to-broadcast/proposal.md` exists.
- Done when: file `openspec/changes/migrate-canvas-realtime-to-broadcast/design.md` exists.
- Done when: file `openspec/changes/migrate-canvas-realtime-to-broadcast/tasks.md` exists.
- Done when: file `openspec/changes/migrate-canvas-realtime-to-broadcast/verification.md` exists.

### Wave 2 — Validation

- Done when: `node tools/check-openspec-refs.mjs` exits 0.

### Wave 3 — Reviewer sign-off

- Reviewer confirms: D-BR-1 split P7a + P7b with a one-week soak gate is the right derisking shape.
- Reviewer confirms: D-BR-2 channel naming `canvas:<id>:<table>` enables selective subscription without per-operation multiplication.
- Reviewer confirms: D-BR-3 bridge conditional path tolerates dual transport during the soak.
- Reviewer confirms: D-BR-4 visibility refetch covers all six HOT tables, not just chat.
- Reviewer confirms: D-BR-5 documented coupling between trigger SQL + JS helper, with round-trip conformance, is preferred over code-gen.
- Reviewer confirms: D-BR-6 migration is idempotent + rollback path is documented.
- Reviewer confirms: D-BR-7 SLOs (p95 ≤ 2s, p99 ≤ 5s) and the 1000-sample size are statistically meaningful.

### Soak gate

- Done when: `bridge_latency_p95_ms ≤ 2000` for 7 consecutive days against the P7a prototype channel.
- Done when: no synthetic-monitor alerts fired during the soak.
- Done when: soak runbook checklist signed off before P7b PR opens.
