Operant Studio
OPER-175

[OPER-QA-5] QA re-run loop (rerun.ts watcher)

Suggested
Justin Cooke

Body

feature_id: FEAT-studio-qa

## Context

The QA primitive is live (OPER-100 landed [REDACTED-DOB]): TestCase / TestRun / TestBugLink / CoverageCell + OPER-129 Ledger Task writer for RUN_TEST assignments. What's missing is the loop-closer: when an auto-dispatched fix ticket completes (Task.status -> DONE), a new TestRun for the covered TestCase should fire automatically so the Coverage Grid's green cells always reflect verification the current head passed, not a stale run against pre-fix code.

Without this loop, every AI-triage auto-dispatch policy is speculative — there's no signal to feed rolling-window auto-demote (3 consecutive rerun failures = demote). The re-run watcher is the primary evidence source for that logic and for Shankar's calibration review of demoted classes at /qa/triage-log.

Plan document already authored at packages/qa/OPER-125-rerun-plan.md. Risk classified Safeguard (Risk 7 / Reach 4): autonomous POSTs to Ledger + test-run dispatch. Silently wrong means duplicate-ticket storm in the dispatch queue or a bug that never re-runs, making the Coverage Grid assert green coverage nothing re-verified.

## Acceptance Criteria

- New module `packages/qa/src/rerun.ts` implements the watcher: subscribes to Task status transitions, for Task.status = DONE where Task has a TestBugLink -> TestCase relation, opens a new TestRun for that TestCase.
- Failure-path tests written BEFORE implementation code, per Build Risk Matrix Safeguard tier discipline. Minimum 16 test cases in `packages/qa/src/rerun.test.ts` covering: duplicate suppression (same Task DONE fires twice), race between watcher and manual re-run, deleted TestCase, orphaned TestBugLink, TestCase whose CoverageCell is disabled, missing agentWorkerId, project without members, and the 9 happy-path variants across TestKind values.
- AuditLog row on every state change: rerun_scheduled, rerun_skipped_duplicate, rerun_skipped_deleted_case, rerun_failed_dispatch. Actor stamp `system:qa-rerun`.
- Drop the OPER-QA-0 `openBugForFailedRun` placeholder in `packages/qa/src/index.ts` — that scaffolding is superseded by this loop.
- README update in `packages/qa/README.md` documenting the loop + closed harm_class vocabulary.
- No schema change, no migration.
- No PHI in scope: Studio stores pointers, ticket body carries ids and enum names only.

## Risk classification

Safeguard (Risk 7 / Reach 4). Failure-path tests before code + AuditLog on every state change, per the Build Risk Matrix.

## Depends on

None — this is the load-bearing loop-closer that unblocks everything downstream (Task.risk_tier schema, AI triage, trace recorder).

## Blocks

- Task.risk_tier schema extension (next ticket)
- AI triage writer + AiTriageClassPolicy + AiTriageLog + auto-demote/promote
- Playwright trace recorder
- /qa/triage-log and /qa/live-fixes canvases

Attachments

Loading attachments…

Comments

Loading comments…