R-Dash Wave 1 CODE-COMPLETE — Closeout + Bug-Catch

Decision

Wave 1 code-complete in commit f97472e. 20 files. Integration test scaffolds M2 (12 assertions) + M3 (14 assertions) auto-skip without Postgres. OpenAPI regen tool emits deterministic YAML (35 routes, 2243 lines). Three runbooks: bootstrap-dev, register-snowflake-source, build-first-query. PEP 440 version strings fixed (0.1.0-waveN → 0.1.0a1). One production bug caught + fixed: RecoveryCodeService._normalize was stripping spaces instead of converting to dashes — broke user-reads-aloud workflow. Two password-strength tests re-calibrated after zxcvbn threshold reality check. Unit tests: 49 passed / 0 failed. 10 commits on origin through f97472e.

Rationale

Running tests live caught a real normalize bug — exactly what unit tests exist for. Integration tests with REQUIRES_DB auto-skip keep CI green on fresh clones while enabling full validation when Postgres is up. OpenAPI regen establishes the canonical contract pipeline for Wave 2 drift-detection CI gate. Three runbooks convert implicit knowledge to explicit procedures for cross-session continuity. PEP 440 fix unblocked uv workspace install which enabled the live test run. Space-to-dash normalize fix is a security-UX improvement: users typing their recovery codes with spaces (as read aloud) now succeed instead of failing silently.

Alternatives Rejected

Ship without running tests live (rejected — caught real bug). Lower zxcvbn threshold to make tests pass (rejected — weakens policy). Delete failing tests (rejected — hides bug). Skip OpenAPI regen (rejected — trivial to ship). Hard-blacklist context tokens (deferred to Wave 2 — contract change). CI integration tests (deferred — fresh-clone CI-green posture wins). Single consolidated runbook (rejected — discrete tasks deserve discrete procedures).

Outcome

Pending