# VS-26: Model Approval Workflow (Maker-Checker Governance) **Vertical Slice:** VS-26 (Model Approval & Activation Gateway) **Version:** 1.0 COMPLETE **Date:** 2026-08-07 **Owner:** Platform Lead + Compliance **Status:** ✅ READY FOR IMPLEMENTATION **Depends On:** VS-02 (data governance) ✅ COMPLETE --- ## 📋 User Story **As a** platform lead / compliance officer **I want to** enforce maker-checker approval workflow for model activation **So that** only reviewed, authorized models reach production (governance compliance) **Acceptance Criteria:** - ✅ Maker: Creates activation proposal (model_id, effective_at, justification) - ✅ Checker: Reviews & approves (adds evidence links: PBO/DSR/OOS) - ✅ SRE: Activates (executes activation command, logs execution) - ✅ State machine: DRAFT → PROPOSED → APPROVED → ACTIVE - ✅ Audit trail: All approvals recorded with timestamp, actor, decision - ✅ Rollback: Activation reversible (deactivate, revert to prior version) --- ## 🎯 Non-Goals - ❌ Implement model training (belongs to separate ML slice) - ❌ Build PBO/DSR calculation (belongs to VS-10, shadow run results) - ❌ Handle rejection workflows (deferred; assume approve or escalate) - ❌ Multi-level approval chains (start with 2-tier: maker + checker) --- ## 🔄 State Machine ``` ┌─────────┐ │ DRAFT │ (Maker creates proposal) └────┬────┘ │ ↓ ┌──────────┐ │ PROPOSED │ (Awaiting checker review) └────┬─────┘ │ ├─→ APPROVED (Checker signs off) → ACTIVE (SRE activates) │ └─→ REJECTED (Checker rejects, returns to DRAFT for revision) ``` --- ## 📊 Data Schema ```sql -- Approval proposals CREATE TABLE model_operations.approval_proposals ( id UUID PRIMARY KEY, model_id UUID NOT NULL REFERENCES model_operations.models(id), status VARCHAR(50) NOT NULL, -- DRAFT, PROPOSED, APPROVED, ACTIVE, REJECTED created_by VARCHAR(255) NOT NULL, -- Maker email created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), justification TEXT NOT NULL, -- Why this model should activate effective_at DATE NOT NULL, -- When to activate (if approved) proposed_at TIMESTAMPTZ, -- When moved to PROPOSED approved_by VARCHAR(255), -- Checker email (if approved) approved_at TIMESTAMPTZ, -- When approved approval_notes TEXT, -- Checker's review notes activated_by VARCHAR(255), -- SRE email (if activated) activated_at TIMESTAMPTZ, -- When activated published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), revision INT NOT NULL DEFAULT 1, correlation_id UUID NOT NULL ); -- Approval evidence (links to PBO/DSR/OOS artifacts) CREATE TABLE model_operations.approval_evidence ( id UUID PRIMARY KEY, approval_proposal_id UUID NOT NULL REFERENCES model_operations.approval_proposals(id), evidence_type VARCHAR(50) NOT NULL, -- PBO_SCORE, DSR_METRIC, OOS_RETURN, BACKTEST_REPORT evidence_url TEXT NOT NULL, -- Path to artifact (logs, files, S3 link) reviewer_comment TEXT, -- Checker's interpretation published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), correlation_id UUID NOT NULL ); -- Approval events (audit trail) CREATE TABLE model_operations.approval_events ( id UUID PRIMARY KEY, approval_proposal_id UUID NOT NULL REFERENCES model_operations.approval_proposals(id), event_type VARCHAR(50) NOT NULL, -- CREATED, PROPOSED, APPROVED, REJECTED, ACTIVATED, DEACTIVATED actor_email VARCHAR(255) NOT NULL, event_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), details JSONB, -- Event-specific details (e.g., rejection reason) published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), correlation_id UUID NOT NULL ); ``` --- ## 🔐 API Contract ### POST /approvals (Create Proposal) **Request:** ```json { "modelId": "uuid", "effectiveAt": "2026-09-15", "justification": "Model passed OOS testing; PBO score 0.95 (confident)" } ``` **Response (201):** ```json { "id": "approval-uuid", "status": "DRAFT", "modelId": "uuid", "createdBy": "maker@company.com", "createdAt": "2026-08-07T10:00:00Z" } ``` ### GET /approvals (List Proposals) **Query Params:** - `status=PROPOSED` (filter by status) - `modelId=uuid` (filter by model) **Response (200):** ```json { "items": [ { "id": "approval-uuid", "modelId": "uuid", "status": "PROPOSED", "createdBy": "maker@company.com", "createdAt": "2026-08-07T10:00:00Z", "justification": "..." } ] } ``` ### POST /approvals/{id}/approve (Checker Approval) **Request:** ```json { "approvalNotes": "PBO verified, OOS metrics acceptable", "evidence": [ {"type": "PBO_SCORE", "url": "s3://evidence/pbo-0.95.json"}, {"type": "OOS_RETURN", "url": "s3://evidence/oos-returns.csv"} ] } ``` **Response (200):** ```json { "id": "approval-uuid", "status": "APPROVED", "approvedBy": "checker@company.com", "approvedAt": "2026-08-07T11:00:00Z" } ``` ### POST /models/{id}/activate (SRE Activation) **Request:** ```json { "approvalProposalId": "approval-uuid" } ``` **Response (202 Accepted):** ```json { "jobId": "activation-job-uuid", "status": "QUEUED", "activatedAt": "2026-09-15T00:00:00Z" } ``` --- ## ✅ Governance Gates ### Pre-Merge Gates - [x] **RBAC Roles Defined:** Maker, Checker, SRE roles assigned - [x] **Approval State Machine:** DRAFT → PROPOSED → APPROVED → ACTIVE - [x] **Evidence Schema:** PBO/DSR/OOS evidence links defined - [x] **Audit Trail:** All events recorded with correlation_id ### Post-Merge Validation (Deferred) - [ ] Integration tests (proposal creation, approval flow) - [ ] RBAC enforcement tests (maker ≠ checker) - [ ] Activation integration (call model activation endpoint) --- ## 🛡️ Security & Compliance **RBAC Enforcement:** - Maker: Can create/revise proposals (own proposals only) - Checker: Can approve proposals (any proposal, must be different user) - SRE: Can activate approved proposals - Audit: All actions logged with actor identity **Compliance:** - ✅ Maker-checker separation (prevents unilateral activation) - ✅ Evidence linkage (traceability to PBO/DSR/OOS) - ✅ Immutable audit trail (for regulatory review) - ✅ Reversibility (can deactivate if issues arise) --- ## 📋 Related Specifications - **VS-00:** PIT envelope (published_at, correlation_id, revision) - **VS-02:** Financial security master (governance foundation) - **VS-27:** Audit trail (event logging) - **VS-10:** Sell decision (uses approved models) --- **Co-Authored-By:** Claude Haiku 4.5 **Status:** ✅ READY FOR IMPLEMENTATION **Next:** VS-27 (audit trail), then Phase 2 implementation