OPER-205
C9 milestone watcher: cron detects first Fiesta UAT close OR Piper DX SaMD event
Suggested
Justin Cooke
Body
--- feature_id: FEAT-studio-pipeline-observability --- ## Context C9 memo (2026.09.10 Studio QA Positioning Shift, Amendment 3) shipped a revised Final Recommendation: position Operant Studio QA externally when the first of two evidence milestones lands — Fiesta UAT external-tester feedback loop closes at least once, OR Piper DX produces SaMD-shaped PSUR evidence. Whichever fires first is the trigger for external-publish reconvene. Neither milestone has an automatic detector today. The C9 memo has no auto-reconvene loop; it relies on a human noticing the milestone and re-opening the memo. That fails the standing rule that every discovered systematic gap should propose a purpose-built gate — this ticket is the gate. Two data sources exist today for automatic detection: 1. **Fiesta UAT close**: `TesterInvite` row (declared in D-28, seeded by POR-773 merged [REDACTED-DOB]) transitions to state `REVIEW_COMPLETE` for the first time in the Fiesta tenant. This is a QaTaskInboxTesterInvite state-machine event that already lands in the audit stream when OPER-127a rerun-loop machines dispatch. 2. **Piper DX SaMD event**: `PSUR` (Periodic Safety Update Report) event emitted from the Piper DX repo's clinical-events stream. Piper DX has an equivalent evidence-emission surface planned but not yet built. For v1 of this watcher, treat any Piper DX repo push tagged `psur:*` OR any Ledger ticket in Piper DX with label `evidence:samd` transitioning to DONE as the trigger. ## What Add a scheduled cron watcher at `apps/web/src/app/api/cron/milestone-c9-external-publish/route.ts` that runs every 15 minutes and: 1. Queries the `TesterInvite` table for any Fiesta-tenant row transitioning to `REVIEW_COMPLETE` since last run. 2. Queries Ledger for any Piper DX task with `evidence:samd` label transitioning to DONE, OR any Piper DX repo push with tag matching `psur:*` (via GitHub Events API `PushEvent` filter). 3. On first detection of either milestone: - Emit `MilestoneFiredEvent` audit row with milestone kind (`fiesta_uat_close` OR `piperdx_samd`), timestamp, evidence pointer (TesterInvite id OR ticket id OR push SHA). - Auto-file a new OPER ticket titled `C9 Reconvene: External-publish trigger fired — <milestone_kind>` under FEAT-studio-pipeline-observability, priority=1, body pre-populated with evidence pointer + link to c9-2026.09.10-studio-qa-positioning-shift.md and the exact Amendment 3 clause. - Post to the shared project Slack channel (per D-28: team-visible, not DM) with the trigger + link to the auto-filed reconvene ticket. - Set a MilestoneWatcher.disabled=true flag so this watcher does not re-file on subsequent detections (it fires exactly once per milestone kind; if BOTH fire on the same tick, file BOTH tickets). Idempotency: keep a `MilestoneWatcher` singleton row with `firstFiestaAt`, `firstPiperDxAt` fields. Non-null means fired. ## Acceptance Criteria - [ ] `MilestoneWatcher` Prisma model added with singleton constraint (`teamId UNIQUE`), fields `firstFiestaAt`, `firstPiperDxAt`, `fiestaEvidenceRef`, `piperdxEvidenceRef`, `disabled` - [ ] Migration adds the model with default row for the operant team - [ ] Cron route runs every 15 minutes at `apps/web/src/app/api/cron/milestone-c9-external-publish/route.ts` - [ ] Route queries TesterInvite for first Fiesta REVIEW_COMPLETE transition - [ ] Route queries Ledger + GitHub for first Piper DX SaMD evidence event - [ ] On first detection: emits MilestoneFiredEvent audit row - [ ] On first detection: auto-files C9 reconvene ticket via Ledger POST - [ ] On first detection: posts to shared project Slack channel - [ ] Watcher fires exactly once per milestone kind (idempotent via MilestoneWatcher row) - [ ] Unit test covers: no-trigger tick, Fiesta-only tick, Piper-only tick, both-on-same-tick, already-fired-no-double - [ ] Integration test with mock TesterInvite + mock PushEvent ## Blocked-by None. Depends on TesterInvite table (already exists per D-28 POR-773 merge). Depends on Piper DX evidence-emission surface, but v1 of this watcher uses the GitHub tag + Ledger label fallback so it does not block on Piper DX repo work. ## Size / Band M / assurance (new cron route, new model, new migration, new watcher pattern that is reusable for future milestone triggers — this is the first Ledger-native milestone watcher). ## Discovered by C9 memo 2026.09.10 Amendment 3 requested a Ledger-milestone reminder tied to first-of Fiesta UAT / Piper DX SaMD. Requested 2026.09.10, filed 2026.09.13. ## Verification Ships when the cron route builds, the migration applies clean, unit + integration tests pass, and a smoke test setting TesterInvite.state to REVIEW_COMPLETE on a fixture Fiesta row triggers the reconvene ticket auto-file within one cron tick.
Attachments
Loading attachments…
Comments
Loading comments…