Files
support_backend/specs/009-problem-resolution/tasks.md
T
saqib mirandClaude Sonnet 5 16daf8d32d feat: implement problem resolution (009)
Populates the five real problem-management stubs (investigation,
root-causes, solutions, verification, resolutions -- problems is
confirmed dead/unwired scaffold and stays untouched) with doc04's
sequential workflow engine:

- investigation: version-row-per-attempt (never overwritten), with a
  customer-safe read path that always strips internalNotes.
- root-causes/solutions/verification: a strict existence chain
  (investigation -> root cause -> solution -> approval -> implementation
  -> verification), each step resolve-or-409 on its own precondition,
  matching doc06's schema field-for-field with no invented columns.
- resolutions: gated on a successfully verified solution (no stored
  solutionId FK, per doc06 -- resolved via a join at write time), moving
  the ticket to RESOLUTION_PENDING_CUSTOMER; explicit customer
  confirmation and a durable auto-close sweep (the previously-unregistered
  CLEANUP queue stub, mirroring 008's breach-detection job) both resolve
  it from there.
- reopen (ticketing/tickets): two real, separately-audited transitions
  (RESOLVED|CLOSED -> REOPENED -> IN_PROGRESS), touching no prior
  problem-resolution record and no SLARun -- closes the loop 008's own
  spec.md left open.

Verification-failure escalation reuses 003/007's existing
HUMAN_ESCALATION transition directly rather than adding an eleventh
trigger type to 008's already-shipped escalation rules.

Customer-facing confirm-resolution/reopen needed a body-shape variant of
002's inbound trust boundary that didn't previously exist:
fastify.authenticateProductIntegration hard-required a full
ticket-creation-shaped body. Extracted the shared token/scope/replay
verification into verifyIntegrationIdentity and added a narrower
authenticateProductIntegrationIdentity decorator + identityOnlyRequestSchema
on top of it -- purely additive, ticket creation's own behavior is
unchanged.

Also fixes a real test-data-hygiene bug surfaced by running this
feature's suite alongside 008's: a wildcard-scoped HierarchyNode and an
intentionally-global SLAPolicy in 008's own test fixtures were silently
affecting other test files' tickets sharing the same live Postgres.

Verified against throwaway Docker Postgres/Redis: typecheck, lint,
architecture-check all clean; full regression (tests/unit +
tests/integration together, 172 tests) passes except the 2 pre-existing
MinIO-dependent attachment failures, unrelated to this feature.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 15:09:29 +05:30

18 KiB

description
description
Task list for 009-problem-resolution

Tasks: Problem Resolution

Input: Design documents from specs/009-problem-resolution/

Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/problem-resolution-contract.md, quickstart.md

Tests: Included as first-class tasks. This feature's pure logic is the existence-chain validation (each step's precondition) and the auto-close due-window predicate; the rest is sequential-workflow wiring best proven end-to-end against real Postgres.

Organization: Tasks are grouped by user story (US1 = P1 investigation, US2 = P1 root cause, US3 = P1 solution states, US4 = P2 verification, US5 = P1 resolution/confirmation/auto-close, US6 = P2 reopen).

Format: [ID] [P?] [Story] Description

All file paths are relative to supporthub-api/ (repo root).


Phase 1: Setup

  • T001 [P] Populate src/modules/problem-management/investigation/ with the full standard shape (controller/, routes/, schema/, repository/, service/, types/, mapper/, constants/, index.ts), replacing the InvestigationService.getInvestigationStatus stub
  • T002 [P] Populate src/modules/problem-management/root-causes/ the same way, replacing the RootCausesService.getRootCause stub
  • T003 [P] Populate src/modules/problem-management/solutions/ the same way, replacing the SolutionsService.getSolutions stub
  • T004 [P] Populate src/modules/problem-management/verification/ the same way, replacing the VerificationService.verifySolution stub
  • T005 [P] Populate src/modules/problem-management/resolutions/ the same way, replacing the ResolutionsService.getResolutions stub — this module additionally gets the auto-close sweep and the two new customer-facing routes (later tasks)
  • T006 [P] Add src/config/problem-resolution.ts (problemResolutionConfig .autoCloseWaitingHours, reading a new RESOLUTION_AUTO_CLOSE_WAITING_HOURS env var, default 72) and register it in src/config/index.ts's re-export list

Phase 2: Foundational (Blocking Prerequisites)

Purpose: Schema for every entity, shared by every user story.

⚠️ CRITICAL: No user-story stage work can begin until this phase is complete.

  • T007 Add Investigation, RootCause, Solution, SolutionImplementation, SolutionVerification, Resolution models to prisma/schema.prisma per data-model.md, plus Problem.investigations/Problem.rootCauses/Problem.solutions and Ticket.resolution back-relations (depends on T001-T005)
  • T008 Run npm run prisma:generate and create the migration (npm run prisma:migrate) for T007 (depends on T007)

Checkpoint: Schema migrated. User stories can now be built.


Phase 3: User Story 1 - Structured investigation, preserved across attempts (Priority: P1) 🎯 MVP (part 1)

Goal: Investigation CRUD with the version-row-per-attempt guarantee and internal-notes exclusion from customer-facing reads.

Independent Test: Quickstart Scenario 1.

Tests for User Story 1

  • T009 [US1] Integration test covering Quickstart Scenario 1 (create, retrieve with every field intact, customer-safe variant omits internalNotes, a second investigation preserves the first) against a real Postgres in tests/integration/problem-resolution-flow.test.ts (depends on T008)

Implementation for User Story 1

  • T010 [US1] Add InvestigationRepository (create, findAllForProblem ordered newest first, findMostRecentForProblem) in investigation/repository/ (depends on T008)
  • T011 [US1] Add Zod create schema (investigator, findings, evidence?, internalNotes?, status?) in investigation/schema/
  • T012 [US1] Add InvestigationService.record/listForProblem (agent-facing, includes internalNotes) and listForProblemCustomerSafe (strips internalNotes, FR-003) in investigation/service/ (depends on T010, T011)
  • T013 [US1] Add POST/GET /admin/problems/:problemId/investigations (gated by fastify.authenticate) and GET /problems/:problemId/investigations (ungated, customer- safe) routes in investigation/controller/ + routes/, registered from src/api/routes.ts (depends on T012)
  • T014 [US1] Run Quickstart Scenario 1 locally and confirm all 3 steps pass

Checkpoint: Investigations can be recorded and read correctly, with the customer-safe redaction guarantee in place.


Phase 4: User Story 2 - Root cause requires an investigation on file (Priority: P1) 🎯 MVP (part 2)

Goal: RootCause CRUD gated on an existing investigation, with a validated type enum.

Independent Test: Quickstart Scenario 2.

Tests for User Story 2

  • T015 [US2] Integration test covering Quickstart Scenario 2 (rejected with no investigation, accepted after one exists, rejected with an invalid type) — implemented as the "Scenario 2" case in tests/integration/problem-resolution-flow.test.ts (depends on T009, T014)
  • T016 [P] [US2] Unit test for the type-validation Zod schema (five valid values, everything else rejected) in tests/unit/problem-management/root-cause-schema.test.ts

Implementation for User Story 2

  • T017 [US2] Add RootCauseRepository (create, findAllForProblem) in root-causes/repository/ (depends on T008)
  • T018 [US2] Add Zod create schema (type as a 5-value enum, description) in root-causes/schema/
  • T019 [US2] Add RootCausesService.record: resolve-or-409 on the problem having at least one investigation (T010's findMostRecentForProblem, via investigation's public index.ts) — in root-causes/service/ (depends on T012, T017, T018)
  • T020 [US2] Add POST /admin/problems/:problemId/root-causes route (gated by fastify.authenticate) in root-causes/controller/ + routes/, registered from src/api/routes.ts (depends on T019)
  • T021 [US2] Run Quickstart Scenario 2 locally and confirm all 3 steps pass

Checkpoint: Root causes are correctly gated on investigation existing first.


Phase 5: User Story 3 - Solution proposed, approved, implemented as distinct states (Priority: P1) 🎯 MVP (part 3)

Goal: Solution CRUD gated on root cause existing; approval as an explicit action; implementation gated on approval, one-to-one.

Independent Test: Quickstart Scenario 3.

Tests for User Story 3

  • T022 [US3] Integration test covering Quickstart Scenario 3 (rejected with no root cause, created with approved: false, implementation rejected before approval, accepted after, a second implementation rejected) — "Scenario 3" case in tests/integration/problem-resolution-flow.test.ts (depends on T015, T021)

Implementation for User Story 3

  • T023 [US3] Add SolutionRepository (create, findById, approve, findMostRecentForProblem) and SolutionImplementationRepository (create, findBySolutionId) in solutions/repository/ (depends on T008)
  • T024 [US3] Add Zod schemas (proposed; implementation's notes?, implementedBy) in solutions/schema/
  • T025 [US3] Add SolutionsService.propose: resolve-or-409 on the problem having at least one root cause (T017's repository, via root-causes's public index.ts) — approverecordImplementation: resolve-or-409 on approved: true and no existing implementation — in solutions/service/ (depends on T019, T023, T024)
  • T026 [US3] Add POST /admin/problems/:problemId/solutions, PATCH /admin/solutions/:solutionId/approve, POST /admin/solutions/:solutionId/implementation routes (gated by fastify.authenticate) in solutions/controller/ + routes/, registered from src/api/routes.ts (depends on T025)
  • T027 [US3] Run Quickstart Scenario 3 locally and confirm all 5 steps pass

Checkpoint: All three P1 record-keeping user stories are complete — the full investigation through implementation chain is enforced and correct. This is the feature's structural MVP.


Phase 6: User Story 4 - Verification, and failure re-investigates or escalates (Priority: P2)

Goal: SolutionVerification CRUD gated on implementation existing, one-to-one; a failed verification supports either a fresh investigation or the existing HUMAN_ESCALATION transition.

Independent Test: Quickstart Scenario 4.

Tests for User Story 4

  • T028 [US4] Integration test covering Quickstart Scenario 4 (successful verification; failed verification recorded but unusable for resolution; failure + reinvestigate creates a fresh Investigation row; failure + escalate transitions the ticket to HUMAN_ESCALATION and 007 auto-assigns) — "Scenario 4" case in tests/integration/problem-resolution-flow.test.ts (depends on T022)

Implementation for User Story 4

  • T029 [US4] Add SolutionVerificationRepository (create, findBySolutionId) in verification/repository/ (depends on T008)
  • T030 [US4] Add Zod schema (method as a 4-value enum, result, evidence?) in verification/schema/
  • T031 [US4] Add VerificationService.record: resolve-or-409 on the solution having an implementation (T023's repository) and no existing verification — in verification/ service/ (depends on T023, T029, T030)
  • T032 [US4] Add POST /admin/solutions/:solutionId/verification route (gated by fastify.authenticate) in verification/controller/ + routes/, registered from src/api/routes.ts (depends on T031)
  • T033 [US4] Run Quickstart Scenario 4 locally and confirm all 4 steps pass (steps 3-4 call T012's InvestigationService.record and ticketsService.updateStatus directly — no new production code beyond what US1/003/007 already provide, per research.md's decision to reuse the existing transition rather than add new escalation machinery)

Checkpoint: Verification is correctly gated and its failure path reuses existing mechanisms rather than inventing new ones.


Phase 7: User Story 5 - Resolution, customer confirmation, and durable auto-close (Priority: P1)

Goal: Resolution gated on a successful verification; explicit customer confirmation via 002's trust boundary; a durable, directly-callable auto-close sweep as the fallback.

Independent Test: Quickstart Scenario 5.

Tests for User Story 5

  • T034 [P] [US5] Unit test for the auto-close due-window predicate (a pending ticket older than the configured waiting period is due; a pending ticket younger than it is not; a non-pending ticket is never selected) in tests/unit/problem-management/auto-close-sweep.test.ts
  • T035 [US5] Integration test covering Quickstart Scenario 5 (resolution rejected without a successful verification; accepted after, ticket reaches RESOLUTION_PENDING_CUSTOMER; customer confirmation via the trust-boundary route reaches RESOLVED; a second ticket aged past the configured window reaches RESOLVED via a direct call to the sweep) — "Scenario 5" case in tests/integration/problem-resolution-flow.test.ts (depends on T028)

Implementation for User Story 5

  • T036 [US5] Add ResolutionRepository (create, findByTicketId) in resolutions/repository/ (depends on T008)
  • T037 [US5] Add Zod schema (outcome, resolvedBy) in resolutions/schema/
  • T038 [US5] Add ResolutionsService.record(ticketId, outcome, resolvedBy): resolves the ticket's problemId, resolve-or-409 on a Solution with verification.result: 'success' existing for it (T023/T029's repositories), creates the Resolution, and transitions the ticket to RESOLUTION_PENDING_CUSTOMER via ticketsService.updateStatus — in resolutions/service/resolutions.service.ts (depends on T023, T029, T036, T037)
  • T039 [US5] Add ResolutionsService.confirmByCustomer(ticketId) / runAutoCloseSweep(): the former transitions RESOLUTION_PENDING_CUSTOMER → RESOLVED directly; the latter queries every RESOLUTION_PENDING_CUSTOMER ticket whose updatedAt is older than problemResolutionConfig.autoCloseWaitingHours and transitions each the same way — a single, directly-callable, side-effect-only method (research.md — no worker process needed to invoke it in tests) — in resolutions/service/resolutions.service.ts (depends on T006, T038)
  • T040 [US5] Add POST /admin/tickets/:ticketId/resolution (gated by fastify.authenticate) and POST /v1/support/tickets/:ticketId/confirm-resolution (gated by fastify.authenticateProductIntegration + fastify.checkIntegrationRateLimit, verifying the token's tenant/user matches the ticket's own — research.md) routes in resolutions/controller/ + routes/, registered from src/api/routes.ts (depends on T038, T039)
  • T041 [US5] Replace registerCleanupWorker()'s stub body in src/jobs/cleanup/index.ts: schedule a repeatable job (every 5 minutes) on QueueName.CLEANUP whose processor calls T039's runAutoCloseSweep — and register it from src/bootstrap/queue.bootstrap.ts (depends on T039)
  • T042 [US5] Run Quickstart Scenario 5 locally and confirm all 4 steps pass

Checkpoint: Every P1 user story is complete. The full investigation-to-resolution chain works, gated correctly at every step, with both an explicit and a durable-fallback path to RESOLVED. This is the feature's MVP.


Phase 8: User Story 6 - Reopen (Priority: P2)

Goal: A resolved or closed ticket can be reopened by the customer or an agent, re-entering IN_PROGRESS through two real, audited transitions, touching nothing else.

Independent Test: Quickstart Scenario 6.

Tests for User Story 6

  • T043 [US6] Integration test covering Quickstart Scenario 6 (customer reopen reaches IN_PROGRESS via REOPENED; the prior Resolution and any SLARun are unchanged; agent reopen of a CLOSED ticket produces the same result attributed to the agent) — "Scenario 6" case in tests/integration/problem-resolution-flow.test.ts (depends on T035)

Implementation for User Story 6

  • T044 [US6] Add TicketsService.reopen(ticketId, actor) (007/003's existing ticketing/tickets module): resolve-or-409 if status isn't RESOLVED/CLOSED, then two sequential updateStatus calls (REOPENED, then IN_PROGRESS) — in ticketing/tickets/ service/tickets.service.ts (depends on T008 — no new schema, reuses 003's own state machine and repository)
  • T045 [US6] Add POST /v1/support/tickets/:ticketId/reopen (customer, trust boundary) and POST /admin/tickets/:ticketId/reopen (agent, fastify.authenticate) routes in ticketing/tickets/controller/ + routes/ (depends on T044)
  • T046 [US6] Run Quickstart Scenario 6 locally and confirm all 4 steps pass

Checkpoint: All six user stories work independently and together — the full doc 04 workflow, from first investigation through resolution, confirmation, auto-close, and reopen.


Phase 9: Polish & Cross-Cutting Concerns

  • T047 [P] Update specs/009-problem-resolution/checklists/requirements.md Notes with any implementation-time findings
  • T048 Run npx tsx scripts/check-architecture.ts and npm run lint/npm run typecheck
  • T049 Full regression: npm run test:unit (scoped to tests/unit) to confirm nothing broke elsewhere, then the full integration suite (including 003's and 007's own suites, since T044 modifies ticketing/tickets) against real Docker-provisioned Postgres/Redis

Dependencies & Execution Order

Phase Dependencies

  • Setup (Phase 1): No dependencies
  • Foundational (Phase 2): Depends on Setup — BLOCKS all user stories
  • User Story 1 (Phase 3): Depends on Foundational — no dependency on US2-US6
  • User Story 2 (Phase 4): Depends on US1 (the investigation it's gated on)
  • User Story 3 (Phase 5): Depends on US2 (the root cause it's gated on)
  • User Story 4 (Phase 6): Depends on US3 (the implementation it's gated on)
  • User Story 5 (Phase 7): Depends on US4 (the successful verification it's gated on)
  • User Story 6 (Phase 8): Depends on US5 (a ticket has to reach RESOLVED/CLOSED before reopening it means anything)
  • Polish (Phase 9): Depends on all six user stories

This feature's user stories are more strictly sequential than 007's or 008's — doc 04's own workflow is a straight chain (investigation → root cause → solution → verification → resolution → reopen), not a set of independently orderable capabilities, so each phase's dependency here is real, not just priority-driven sequencing.

Parallel Opportunities

  • T001-T006 (independent scaffolding)
  • T016 (unit test) alongside T017-T018 (the schema it tests)
  • T034 (unit test) alongside T039 (the sweep it tests)
  • T047 in Polish

Implementation Strategy

MVP First (User Stories 1-3, then 5)

  1. Setup + Foundational (T001-T008)
  2. User Story 1 (T009-T014) → investigations recorded and readable
  3. User Story 2 (T015-T021) → root causes correctly gated
  4. User Story 3 (T022-T027) → solutions proposed/approved/implemented correctly
  5. User Story 4 is P2 — skippable for a first MVP cut if verification's own gating isn't needed yet, but User Story 5 (Resolution) depends on it structurally (a successful verification is Resolution's own precondition), so in practice build order is 1→2→3→4→5 regardless of priority label — same "dependency order isn't always priority order" note 006 and 007's own tasks.md already made.
  6. User Story 5 (T034-T042) → resolution, confirmation, and auto-close all work
  7. STOP and VALIDATE: Quickstart Scenarios 1-5 pass.

Incremental Delivery

  1. Setup + Foundational → schema migrated
  2. Add User Story 1 → investigations exist
  3. Add User Story 2 → root causes correctly gated
  4. Add User Story 3 → solutions move through real states
  5. Add User Story 4 → verification gated, failure path reuses existing mechanisms
  6. Add User Story 5 → resolution + confirmation + auto-close (P1-complete, MVP)
  7. Add User Story 6 → reopen, closing the loop 008 left open
  8. Polish → full regression