Operant Studio
OPER-176

Add Task.risk_tier enum column for AI-triage auto-dispatch policy

Band
MEDIUM
Suggested
Justin Cooke

Body

feature_id: FEAT-studio-qa

## Context

PDT memo v5 ([REDACTED-DOB]) approved the AI-triage auto-dispatch policy for QA-reported bugs. The policy keys off the existing Build Risk Matrix (Sandbox / Scaffold / Safeguard / Stronghold). To make that policy machine-executable at ticket-creation time, Task needs a `risk_tier` enum column derived from the touched files' risk annotations + PHI floor check + severity check.

Without this column, the AI triage writer has nowhere to persist its risk classification, and downstream code (should_auto_dispatch decision, AiTriageClassPolicy lookup, AiTriageLog rows) has no join key. This is the schema foundation for the entire auto-dispatch flow.

## Acceptance Criteria

- Add enum `RiskTier { SANDBOX, SCAFFOLD, SAFEGUARD, STRONGHOLD }` in appropriate prisma schema file under `packages/database/prisma/schema/`.
- Add optional column `risk_tier RiskTier?` to Task model. Nullable because historical tickets pre-date the classifier.
- Migration file added under `packages/database/prisma/migrations/`, following the existing snake_case + @map() naming convention per OPERANT-BOILERPLATE.md.
- Backfill: NOT required in this ticket. Backfill script for historical tickets is a follow-up if/when we need to compute analytics over pre-existing tickets. Nullable column allows incremental population.
- Helper function `deriveRiskTier(evidenceTrace, suggestedPatchFilePaths, severity): RiskTier` in `packages/qa/src/risk-tier.ts` implementing the derivation logic:
  - If severity is BLOCKER: return SAFEGUARD (BLOCKER goes to human via override, but tier itself is still classified for reporting).
  - If any URL in evidence.trace.network matches `/api/phi/*` OR any file in suggestedPatchFilePaths is annotated `@risk-tier: stronghold`: return STRONGHOLD (PHI floor rule).
  - Otherwise use `@risk-tier:` annotation on the touched files. Highest tier wins across the fileset.
  - Default to SAFEGUARD if no annotations found (fail-safe: unknown code paths get failure-path-test discipline).
- Unit tests for deriveRiskTier covering all four tier outcomes + BLOCKER override + PHI floor + missing-annotation default. Failure-path tests first per Build Risk Matrix.
- AuditLog row on every risk_tier assignment: actor `system:qa-risk-tier-classifier`.

## Risk classification

Safeguard (Risk 7 / Reach 5). Schema change on Task is high-blast-radius because every downstream module reads Task rows. Failure-path tests before code + AuditLog per Build Risk Matrix.

## Depends on

OPER-175 (rerun watcher) — must land first because the auto-demote logic in the AI triage ticket depends on RERUN_PASS / RERUN_FAIL events being emitted by rerun.ts.

## Blocks

- AI triage writer + AiTriageClassPolicy + AiTriageLog + auto-demote/promote (next ticket)
- Playwright trace recorder (depends transitively — needs risk_tier to classify its output)

Attachments

Loading attachments…

Comments

Loading comments…