Operant Studio
OPER-98

[OPER-QA-2] Test Projects + Phases + Members over the existing QA primitive

Band
MEDIUM
Suggested
Justin Cooke

Body

feature_id: FEAT-QA-PROJECTS-PHASES-MEMBERS

## Context

Follow-up to OPER-QA-0 (ratified [REDACTED-DOB]). The OPER-QA-0 primitive shipped as scaffold: 8 models (TestSuite / TestCase / TestRun / TestResult / TestAssignment / CoverageCell / TestFixtureRef / TestBugLink), migration, barrel exports. There is no way today to group TestCases into a scoped, sequenced execution surface for external testers (Fiesta UAT: Ana Torres, Hannah Clement). This ticket adds the missing project/phase/member layer WITHOUT duplicating the existing Ledger Task concept — tester actions (RUN_TEST, RETEST_BUG, REVIEW_FAILURE, ANSWER_CLARIFICATION, REVIEW_EVIDENCE, ATTEST_PHASE_COMPLETE) remain Ledger Tasks with labels, not a new polymorphic table.

Risk classification per build-risk-matrix.md: Stronghold on the schema layer (high risk, high reach: multi-tenant Studio teams, cross-product foundation, auto-called by dispatcher). Companion Portico UI ticket (POR-N) is Safeguard.

Full spec: docs/plans/OPER-QA-2-projects-phases-tasks-inbox.md (drafted [REDACTED-DOB]; committed alongside PR 1).

## Scope

**In-scope (this ticket, split across 2 PRs per pr-size-budget.md):**

- 3 new models in packages/database/prisma/schema/qa.prisma: TestProject, TestPhase, TestProjectMember
- 5 new enums: TestProjectStatus, TestPhaseState, TestMemberRoleClass (2 reused)
- Migration with RLS policies on all 3 tables (organization_id + current_org_id())
- packages/qa/src/projects.ts server helpers (createTestProject, addTestProjectMember, activateTestPhase, listPhasesForMember)
- API routes: /api/studio/[team]/qa/projects (GET, POST), /projects/[id]/phases, /projects/[id]/members
- Zod validators
- 10 failure-path tests written BEFORE implementation (Stronghold rule)

**Out of scope (follow-up tickets):**

- Task type UIs beyond RUN_TEST (RETEST_BUG, REVIEW_FAILURE, ANSWER_CLARIFICATION, REVIEW_EVIDENCE, ATTEST_PHASE_COMPLETE) — Ledger Task labels only for v0.1
- QA Runner overlay (separate PDT-approved ticket family)
- Seed data for Fiesta UAT · Ana + Fiesta UAT · Hannah Clement (separate seed PR after schema lands)
- Portico autogen from Feature Map (OPER-QA-1 already named)
- QA Tests menu tab UI (Coverage Grid, Test Library, Run Queue, Bug Board) — already named as follow-ups in [REDACTED-DOB] PDT
- Email notifications (Studio missing 6 of 9 boilerplate packages including @operant/email)
- Automatic phase advance (v0.2)
- Cross-tenant flex identity for external testers who work at multiple client sites (v0.2)

## PR plan

- PR 1 (M): schema + migration + failure-path test scaffolding (10 cases as .skip)
- PR 2 (M, stacked on PR 1): server implementation + un-skip all 10 tests + eslint no-phi-in-template rule

## Acceptance Criteria

- [ ] 3 new tables land in packages/database/prisma/schema/qa.prisma with cuid() PKs, snake_case @map(), createdAt/updatedAt, organization_id on every row
- [ ] Migration 20260904_oper_qa_2_projects_phases_members applies cleanly and creates RLS policies USING (organization_id = current_org_id()) on all 3 tables
- [ ] No PHI columns; no `/// @PHI` annotations required (verified by phi-auditor)
- [ ] check-org-scoped CI passes; no allowlist changes needed
- [ ] All 10 failure-path tests pass (bad input, API down, expired auth, zero-unit data, cross-tenant leak, PHI-in-template lint, offline audit queue, etc. — enumerated in plan doc)
- [ ] All 13 auto-loaded reviewers return Ready (phi-auditor, rls-guard, schema-guard, migration-safety, test-quality-reviewer, security-auditor, dependency-safety, performance-reviewer, simplification-reviewer, code-reviewer, docs-manager, sentinel, tester)
- [ ] Both PRs size/M or smaller per pr-size-budget.md; PR 2 stacked on PR 1 branch
- [ ] Rollback verified: DROP TABLE + DROP TYPE reverses migration cleanly; no impact on existing OPER-QA-0 rows
- [ ] docs/plans/OPER-QA-2-projects-phases-tasks-inbox.md committed in PR 1
- [ ] Portico companion POR ticket blocked_by this ticket until PR 2 merges

## Blocks

Portico `<QATaskInbox />` component ticket (POR-N, filed separately) — cannot start until PR 2 merges and Studio QA API endpoints are live.

---
<!-- admission-rejected -->
**Admission rejected (unknown_feature_id):** feature_id=FEAT-QA-PROJECTS-PHASES-MEMBERS is not declared in the feature-map.md of any admission-enabled product owned by this team

Attachments

Loading attachments…

Comments

Loading comments…