---
phase: 12
slug: native-tablo-chat
status: complete
nyquist_compliant: true
wave_0_complete: true
created: 2026-05-16
---

# Phase 12 - Validation Strategy

> Per-phase validation contract for native tablo discussion.

## Test Infrastructure

| Property | Value |
|----------|-------|
| **Framework** | Go test with existing DB-backed integration harness |
| **Config file** | `backend/sqlc.yaml`, `backend/justfile` |
| **Quick run command** | `cd backend && go test ./internal/web -run 'TestDiscussion|TestTablosListDiscussionUnread' -count=1` |
| **Full suite command** | `cd backend && TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./... -count=1` |
| **Estimated runtime** | ~60 seconds for full backend suite with local Postgres |

## Sampling Rate

- **After every task commit:** Run the targeted discussion test command for touched behavior.
- **After every plan wave:** Run `cd backend && just generate` plus the full backend suite.
- **Before `$gsd-verify-work`:** Full suite and browser/SSE UAT must be green.
- **Max feedback latency:** 60 seconds for automated checks.

## Per-Task Verification Map

| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status |
|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------|
| 12-01-01 | 01 | 1 | CHAT-03 | T-12-01/T-12-02 | Message schema carries tablo/author/body/timestamps/edit/delete metadata | integration | `cd backend && go test ./internal/web -run 'TestDiscussionSchemaIncludesLifecycleMetadataAndBodyConstraints' -count=1` | Yes | COVERED |
| 12-01-02 | 01 | 1 | CHAT-01/CHAT-02/CHAT-06 | T-12-03/T-12-04/T-12-05 | Owner-only history and POST validation with escaped output | integration | `cd backend && go test ./internal/web -run 'TestDiscussion' -count=1` | Yes | COVERED |
| 12-01-03 | 01 | 1 | CHAT-01/CHAT-06 | T-12-05 | UI contract renders escaped history, day separators, composer, and fallback | integration | `cd backend && go test ./internal/web -run 'TestDiscussion' -count=1` | Yes | COVERED |
| 12-02-01 | 02 | 2 | CHAT-01 | T-12-06 | Unread count comes from persistent owned read state | integration | `cd backend && go test ./internal/web -run 'TestTablosListDiscussionUnread|TestDiscussion.*Read' -count=1` | Yes | COVERED |
| 12-02-02 | 02 | 2 | CHAT-01 | T-12-06/T-12-07 | Dashboard badge shows only accurate unread counts | integration | `cd backend && go test ./internal/web -run 'TestTablosListDiscussionUnread' -count=1` | Yes | COVERED |
| 12-03-01 | 03 | 3 | CHAT-04/CHAT-05 | T-12-08/T-12-09 | Authenticated SSE streams flush owned message events without external provider | integration/manual | `cd backend && go test ./internal/web -run 'TestDiscussionStream|TestDiscussionBroker|TestDiscussionPostBroadcasts|TestDiscussionStaticScript' -count=1` | Yes | COVERED |
| 12-03-02 | 03 | 3 | CHAT-04/CHAT-05 | T-12-08/T-12-10 | Two browser views receive messages without refresh through local/prod proxy path | manual | Browser UAT approved 2026-05-16 | N/A | COVERED |

## Wave 0 Requirements

Existing infrastructure covers all phase requirements:

- `backend/internal/web/testdb_test.go` provides DB-backed schema-isolated tests.
- `backend/internal/web/handlers_events_test.go` provides full-router authenticated child-resource patterns.
- `backend/justfile` provides `just generate`, `just test`, and local dev server workflows.

## Manual-Only Verifications

| Behavior | Requirement | Why Manual | Test Instructions |
|----------|-------------|------------|-------------------|
| Two open browser views receive new discussion messages without manual refresh | CHAT-04 | Requires real browser EventSource behavior and DOM updates | Open the same tablo discussion in two tabs/sessions, send a message in one, confirm the other appends it without refresh and sender does not duplicate it. |
| Streaming through reverse proxy path is not buffered | CHAT-04/CHAT-05 | `httptest` cannot prove proxy buffering/keepalive behavior | Run the app behind the local/prod reverse proxy path, keep the stream open, send a message, confirm delivery and keep-alive behavior. |

## Validation Sign-Off

- [x] All tasks have `<automated>` verify or manual-only justification.
- [x] Sampling continuity: no 3 consecutive tasks without automated verify.
- [x] Wave 0 covers all missing test infrastructure references.
- [x] No watch-mode flags.
- [x] Feedback latency target < 60s.
- [x] `nyquist_compliant: true` set in frontmatter.

**Approval:** audited 2026-05-16

## Validation Audit 2026-05-16

| Metric | Count |
|--------|-------|
| Gaps found | 1 |
| Resolved | 1 |
| Escalated | 0 |

### Gap Filled

- Added `TestDiscussionSchemaIncludesLifecycleMetadataAndBodyConstraints` in `backend/internal/web/handlers_discussion_test.go` to verify `discussion_messages` lifecycle metadata columns and direct database body constraints required by CHAT-03/CHAT-06.

### Final Verification

- `cd backend && TEST_DATABASE_URL='postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable' go test ./internal/web -run 'TestDiscussionSchemaIncludesLifecycleMetadataAndBodyConstraints|TestDiscussion' -count=1`
