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:
@@ -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
|
||||
Reference in New Issue
Block a user