MOTIR-137Done
2.6.3 Full Epic-2 lifecycle integration scenario (vitest)
Estimate: 35m · Depends on: 2.6.1
Add tests/integration/work-items/epic2-lifecycle.test.ts — a single cross-story scenario that threads the whole Epic-2 lifecycle end to end, the integration journey no individual 2.x test owns (each owns a slice). All through workItemsService against real Postgres.
The scenario:
- Build a full tree honoring the kind-parent matrix: create an
epic, astoryunder it, ataskunder the story, abugunder the task, and asubtaskunder the bug (exercising the legal parent chain to the 4-level depth cap; assert each lands with the rightparentId, a gap-free per-projectkey, and a derivedPROD-<n>identifier). - Assign items to a workspace member (and confirm a non-member assignee is rejected with
AssigneeNotInWorkspaceError— the assignee gate in a lifecycle context). - Walk a representative item through a multi-hop status lifecycle under restricted policy:
todo → in_progress → in_review → done, then a block/unblock detour (in_progress ↔ blocked), then a reopen (done → in_progress). Assert each hop validates and records anupdatedrevision, and that an illegal jump mid-walk (e.g.todo → done) raisesIllegalTransitionErrorwithout mutating status. - Archive a leaf and assert the soft-delete leaves children intact (Linear shape — no cascade) and that the archived item drops out of the default list/tree reads.
- Assert the read surfaces reflect the final state:
getProjectTreereturns the nested forest with correct depths and the archived item excluded;getProjectIssuesList(paginated/filtered) returns the live items with the right statuses + assignees;isReadyis correct for an item with/without open blockers.
This is an INTEGRATION scenario, not unit re-coverage — it asserts the pieces compose. Reuse the shared fixtures (do not re-inline helpers).
Acceptance criteria
- New file
tests/integration/work-items/epic2-lifecycle.test.ts; passes underpnpm teston real Postgres. - The full epic→story→task→bug→subtask chain is created through the service and asserted (parentage, gap-free keys, derived identifiers, depth).
- The multi-hop status walk covers forward + block/unblock + reopen, each writing a revision; a mid-walk illegal transition is rejected without mutation.
- Assignee gate exercised (member assigns; non-member rejected with
AssigneeNotInWorkspaceError). - Archive leaves children intact and the item is excluded from
getProjectTree+getProjectIssuesListdefaults. - Final
getProjectTree,getProjectIssuesList, andisReadyreads assert the end state. - Uses
tests/fixtures/*(no re-inlined setup); eachdescribe/itnames the behavior.
Context refs
lib/services/workItemsService.ts—createWorkItem,assignWorkItem,updateStatus,archiveWorkItem,getProjectTree,getProjectIssuesList,isReadylib/workItems/errors.ts—AssigneeNotInWorkspaceError,IllegalTransitionError,IllegalParentTypeErrortests/integration/work-items/{service,project-tree,issue-list-view}.test.ts— the sliced coverage this composes (do not duplicate)tests/fixtures/{workItemFixtures,projectFixtures,workspaceFixtures,userFixtures}.ts,tests/helpers/db.tsprisma/sql/work_item_triggers.sql— kind-parent / depth rules the create chain rides