R-Dash Wave 2 Pass 2 — M4/M5 Routes + First RLS Contract Test (J3 First Instance)
Decision
Wave 2 pass 2 shipped in commit e09da84 (2026-04-17). 13 files / +1621 lines. M4 Semantic fully implemented (YAML safe_load + structural validation + metric extraction + schema-file sync to mounted Cube dir + version bumping + pure-replace registry; routes gated by workspace+admin roles). M5 Governance fully implemented (RLSPolicyService with runtime contract-test-path verification refusing activation if file absent; ColumnMaskService with DB uniqueness; CertificationService with author!=certifier SoD raising CertificationSelfError; SensitivityLabelService idempotent apply; 5 sub-routers with differentiated role gates). First production-shape RLS contract test sales-region-scope with 6 assertions (3 personas × exact row counts + cross-scope leak assertion + fail-closed missing-claim + injection-resistance). Dedicated CI workflow rls-contract-tests.yml with zero-test guard. pytest marker rls_contract registered. main.py wires semantic_router + governance_router at /api/v1. Unit tests 80/80 green (49 prior + 25 policy engine + 6 contract).
Rationale
J3 acceptance criterion first instance achieved — canonical 6-assertion template future policies clone. Runtime contract-test-path verification means dual gate (CI + runtime) — no policy activatable without paired test. Certification SoD enforced in service code not just documentation. YAML structural validation refuses malformed schemas before they corrupt Cube’s mounted dir. Role gates differentiated per sub-router: RLS/mask admin-tier only (catastrophic blast radius), certification includes workspace-owner (closer to content), audit read includes audit-reader (compliance read-only). Zero-test CI guard prevents silent gate disablement. Tableau MCP reference-only per ADR-0002 Snowflake-only — SemanticMetric format_spec mirrors Tableau Pulse Metric Definition schema for future migration optionality but zero runtime coupling.
Alternatives Rejected
No runtime contract-test check (rejected — belt-and-braces). Same-user self-certify (rejected — SoD non-negotiable). Auto-activate RLS on create (rejected — admin must explicitly flip is_active). Skip YAML structural validation (rejected — malformed YAML crashes Cube). Platform-admin only for certification (rejected — workspace-owner is closer). Skip zero-test CI guard (rejected — silent gate disablement is worst failure mode). Hand-written Cube JSON schema vs safe_load (rejected — upstream owns Cube spec). Column mask without uniqueness (rejected — ambiguous). Tableau MCP runtime data source (rejected per ADR-0002). CRUD without audit viewer (rejected — audit read is part of governance contract).
Outcome
Pending
Related
- R-Dash Wave 2 Pass 1
- R-Dash Wave 1 CODE-COMPLETE