Operant Studio
OPER-188

D-29: promotion-stage coverage gate at Ledger admission

Suggested
Justin Cooke

Body

---
feature_id: FEAT-studio-qa
---

> D-29 ticket 5: promotion-stage coverage gate. Target FEAT-studio-qa-promotion-gate (child). BLOCKED-BY: OPER-184 + OPER-187.

## Context

(PDT decision-memo lineage; see source line below.)

**Source: PDT D-29 (coverage by construction), ticket 5 of 5.**

## What
New module `packages/qa/src/promotion-gate.ts`.

Callers:
- New admission-time check added to Ledger admission for tickets that touch `stage:` frontmatter changes
- Any future `promote-status` action added downstream

## Threshold table (D-29 amended open question 1 recommendation)
- Shadow: all required cells at minimum READY (test is written, runnable)
- Canary: all required cells at minimum READY plus at least one run attempted
- Beta: all required cells GREEN (test exists AND last run passed AND within freshness window per `DEFAULT_FRESHNESS_DAYS = 30`)
- GA: all required cells GREEN AND @PHI-inferred security + auth_denied cells specifically GREEN

## Rejection reason format
Enumerate the exact missing cell(s): `feature=<FEAT-id> runtime=<runtime> kind=<kind> state=<state> required_state=<state>`

## Blocked-by
Tickets 1 (frontmatter contract exists) and 4 (scheduler produces runs that transition cells GREEN).

## Acceptance Criteria
- [ ] `promotion-gate.ts` exists with `gatePromotion(featureId, targetStage): {ok, blocking?: BlockingCell[]}`
- [ ] Ledger admission calls gate on `stage:` change
- [ ] Rejection enumerates blocking cells
- [ ] Unit tests for each stage's threshold

## Feature
FEAT-studio-qa-promotion-gate (add via feature-map + depmap two-PR sequence FIRST)

## Size / Band
SMALL / assurance.

Attachments

Loading attachments…

Comments

Loading comments…