Workstream H: Implement VS-03 Approval Workflow (Maker-Checker governance)

- 3 API endpoints: POST /approvals, GET /approvals, POST /approvals/{id}/approve
- State machine: DRAFT → PROPOSED → APPROVED → ACTIVE
- RBAC enforcement: Maker ≠ Checker separation of duties
- Evidence linkage: PBO/DSR/OOS artifact URLs stored
- Schema: Append-only events with correlation_id
- Tests: 5+ unit/integration scenarios
- Documentation: Full API contracts + compliance procedures
- AGENTS.md v16.0 13/13 compliance 

Closes workstream H (Phase 2 implementation).

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 16:38:14 +09:00
parent 2b2841671c
commit a2e742c78d
8 changed files with 1327 additions and 0 deletions
@@ -0,0 +1,208 @@
# 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 <noreply@anthropic.com>
**AGENTS.md v16.0:** 13/13 ✅
**Compliance:** Spec-before-code, no new tech debt