Files
KArtSell.Aegis/docs/CURRENT/SLICE_SPECS/VS-26-SLICE_SPEC.md
T
kjh2064 cedc8d79ee docs: resolve VS-03/04/12/14 numbering collision (renumber to VS-26/27/28/29)
Renumbers the four 2026-08-07 slices (ApprovalWorkflow, AuditTrail,
TradeExecution, PortfolioReconciliation) to previously-unused VS-26..29,
leaving WBS_MASTER.csv's original VS-03/04/12/14 definitions (IngestMarketDataPIT,
ApplyCorporateActions, RankBuyCandidates, GenerateDailyRecommendations) untouched,
per docs/DECISIONS/ADR-WBS-001-slice-renumbering.md.

While investigating, found two things not yet resolved by this commit:
- DEBT-017 (duplicate ApprovalWorkflow implementation): the tested backend
  (ApprovalWorkflow/) is [DontRegister]'d dead code; the live one
  (Features/ApprovalWorkflow/, wired in Program.cs) has no dedicated tests.
  AEG-VS-26-01 downgraded from COMPLETED to BLOCKED in the tracker pending an
  architect decision on which implementation is canonical.
- Features/MarketData and Features/Portfolio (VS-03/04/05/08 Market Data
  Ingestion Dashboard, Portfolio Rebalance, Risk Metrics, Dashboard) are a
  third, already-implemented-and-tested body of work entirely absent from
  WBS_PROGRESS_TRACKER.csv. Flagged in CURRENT_ROADMAP.md as a follow-up.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-08 12:36:00 +09:00

6.6 KiB

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

-- 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:

{
  "modelId": "uuid",
  "effectiveAt": "2026-09-15",
  "justification": "Model passed OOS testing; PBO score 0.95 (confident)"
}

Response (201):

{
  "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):

{
  "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:

{
  "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):

{
  "id": "approval-uuid",
  "status": "APPROVED",
  "approvedBy": "checker@company.com",
  "approvedAt": "2026-08-07T11:00:00Z"
}

POST /models/{id}/activate (SRE Activation)

Request:

{
  "approvalProposalId": "approval-uuid"
}

Response (202 Accepted):

{
  "jobId": "activation-job-uuid",
  "status": "QUEUED",
  "activatedAt": "2026-09-15T00:00:00Z"
}

Governance Gates

Pre-Merge Gates

  • RBAC Roles Defined: Maker, Checker, SRE roles assigned
  • Approval State Machine: DRAFT → PROPOSED → APPROVED → ACTIVE
  • Evidence Schema: PBO/DSR/OOS evidence links defined
  • 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)

  • 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 noreply@anthropic.com
Status: READY FOR IMPLEMENTATION
Next: VS-27 (audit trail), then Phase 2 implementation