# VS-03: Model Approval Workflow ## Overview This vertical slice implements a maker-checker approval workflow for model activation. It enforces separation of duties, state machine transitions, and evidence linkage for regulatory compliance. **Status:** ✅ Ready for implementation **Specification:** `docs/CURRENT/SLICE_SPECS/VS-03-SLICE_SPEC.md` --- ## 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). --- ## Key Features ### 1. Approval State Machine ``` DRAFT (Maker creates) ↓ PROPOSED (Maker submits to Checker) ├→ APPROVED (Checker signs off with evidence) │ ↓ │ ACTIVE (SRE activates) │ └→ REJECTED (Checker rejects, revise to DRAFT) ``` ### 2. Maker-Checker Separation of Duties - **Maker:** Can create and propose approval proposals (own proposals only) - **Checker:** Can approve any proposal (must be different from Maker) - **SRE:** Can activate approved proposals - **System:** Logs all actions with actor identity and correlation_id ### 3. Evidence Linkage - Store PBO/DSR/OOS artifact URLs during approval - Checker annotates evidence interpretation - Traceability: approval_id → evidence_links → S3 artifacts ### 4. Immutable Audit Trail - All state transitions logged in `approval_events` table - Correlation_id links related events - PIT tracking via `published_at` + `revision` --- ## Database Schema ### approval_proposals ```sql id, model_id, status, created_by, created_at, justification, effective_at, proposed_at, approved_by, approved_at, approval_notes, activated_by, activated_at, published_at, revision, correlation_id ``` ### approval_evidence ```sql id, approval_proposal_id, evidence_type, evidence_url, reviewer_comment, published_at, correlation_id ``` ### approval_events ```sql id, approval_proposal_id, event_type, actor_email, event_at, details, published_at, correlation_id ``` --- ## API Endpoints ### POST /approvals (Create Proposal) **Role:** Maker **Request:** ```json { "modelId": "uuid", "effectiveAt": "2026-09-15", "justification": "Model passed OOS testing; PBO score 0.95" } ``` **Response (201):** ```json { "id": "approval-uuid", "modelId": "uuid", "status": "Draft", "createdBy": "maker@company.com", "createdAt": "2026-08-07T10:00:00Z" } ``` ### GET /approvals (List Proposals) **Query Params:** `status=Proposed&modelId=uuid` **Response (200):** ```json { "items": [ { "id": "approval-uuid", "modelId": "uuid", "status": "Proposed", "createdBy": "maker@company.com", "approvalNotes": null } ] } ``` ### GET /approvals/{id} (Get Single) **Response (200):** ```json { "id": "approval-uuid", "modelId": "uuid", "status": "Proposed", "evidence": [ { "id": "evidence-uuid", "evidenceType": "PBO_SCORE", "evidenceUrl": "s3://evidence/pbo-0.95.json", "reviewerComment": "Verified" } ] } ``` ### POST /approvals/{id}/approve (Checker Approval) **Role:** Checker **Request:** ```json { "approvalNotes": "PBO verified, OOS metrics acceptable", "evidence": [ {"type": "PBO_SCORE", "url": "s3://evidence/pbo-0.95.json", "comment": "Verified"}, {"type": "OOS_RETURN", "url": "s3://evidence/oos-returns.csv", "comment": "Acceptable"} ] } ``` **Response (200):** ```json { "id": "approval-uuid", "status": "Approved", "approvedBy": "checker@company.com", "approvedAt": "2026-08-07T11:00:00Z" } ``` --- ## RBAC Enforcement | Role | Can Create | Can Approve | Can Activate | |------|-----------|-----------|------------| | Maker | ✅ (own) | ❌ | ❌ | | Checker | ❌ | ✅ (others) | ❌ | | SRE | ❌ | ❌ | ✅ | | Admin | ✅ | ✅ | ✅ | **Separation of Duties:** Maker ≠ Checker (same user cannot approve own proposal) --- ## Compliance & Governance - ✅ **Separation of Duties:** Enforced at Endpoint level - ✅ **Evidence Linkage:** All evidence URLs traceable to artifacts - ✅ **Immutable Audit Trail:** INSERT-only events table - ✅ **Correlation Tracking:** CorrelationId links related events across slices - ✅ **PIT Queries:** All reads include `WHERE published_at <= cutoff` --- ## Related Specifications - **VS-00:** PIT envelope (published_at, correlation_id, revision) - **VS-02:** Financial security master (governance foundation) - **VS-04:** Audit trail (logs all approval events) - **VS-10:** Sell decision (uses approved models) --- ## Next Steps 1. ✅ Schema migration (0036_approval_workflow.sql) 2. ✅ Domain entities (ApprovalProposal, ApprovalEvidence, ApprovalEvent) 3. ✅ Dapper queries (Sql.cs) 4. ✅ Business logic (ApprovalPolicy with state machine) 5. ✅ HTTP handlers (ApprovalHandlers.cs) 6. ✅ FastEndpoints (ApprovalEndpoints.cs) 7. ✅ Unit/Integration tests 8. ⏳ Merge to main (awaiting PR review) 9. ⏳ Integration with VS-04 (audit trail subscribers) 10. ⏳ Phase 2 implementation (after Phase 1 data available) --- **Co-Authored-By:** Claude Haiku 4.5 **AGENTS.md v16.0:** 13/13 ✅ **Compliance:** Spec-before-code, no new tech debt