docs: spec for problem resolution feature (009)
Investigation -> Root Cause -> Solution -> Implementation -> Verification -> Resolution, plus customer confirmation and reopen, matching doc04 SS3-9's workflow narrative and doc06's "Domain: Problem Resolution" schema exactly. Explicitly closes a loop 008's own spec left open (reopen never restarts an SLA run); verification-failure escalation reuses 003/007's existing HUMAN_ESCALATION transition rather than adding an eleventh escalation-rule trigger type to 008's system. Also documents a real scope-boundary finding: src/modules/problem-management/problems is a dead, unwired duplicate scaffold for Problem (the real one has lived in ticketing/tickets since 003) and is not touched by this feature -- only the five investigation/root-causes/solutions/resolutions/verification stub directories are. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
7e3d2ae29f
commit
14c6793460
@@ -0,0 +1,52 @@
|
||||
# Specification Quality Checklist: Problem Resolution
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2026-09-03
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Scope is Phase 9 per `docs/10-implementation-roadmap.md`: Investigation → Root Cause →
|
||||
Solution → Solution Implementation → Solution Verification → Resolution, plus customer
|
||||
confirmation and reopen — the full doc 04 §3-9 workflow narrative, matching doc 06's "Domain:
|
||||
Problem Resolution" schema exactly (no new fields invented beyond what's already documented).
|
||||
- `src/modules/problem-management/{investigation,root-causes,solutions,resolutions,verification}`
|
||||
are the five real target stub directories for this feature (each currently a one-file stub
|
||||
returning a hardcoded placeholder). `src/modules/problem-management/problems` was found to be a
|
||||
**dead, unwired duplicate scaffold** for `Problem` — the real, actively-used `Problem` model and
|
||||
repository already live in `ticketing/tickets` since 003 — this feature does not touch
|
||||
`problem-management/problems`, matching this session's established discipline of only replacing
|
||||
stubs a documented phase's roadmap item actually calls for.
|
||||
- This feature explicitly closes a loop 008-sla-escalation's own spec.md left open in its Edge
|
||||
Cases: "reopening... may need its own SLA-run-restart decision" — resolved here as "no new SLA
|
||||
run on reopen" (FR-018), keeping 008's already-shipped 1:1-with-first-assignment boundary
|
||||
unchanged rather than reopening (no pun intended) that feature's own scope.
|
||||
- Verification-failure escalation deliberately reuses 003/007's existing `HUMAN_ESCALATION`
|
||||
transition rather than inventing a new escalation-rule trigger type in 008's system — flagged
|
||||
explicitly in Assumptions as a scope decision, not an oversight.
|
||||
- All items pass; no revision iterations were needed.
|
||||
@@ -0,0 +1,315 @@
|
||||
# Feature Specification: Problem Resolution
|
||||
|
||||
**Feature Branch**: `009-problem-resolution`
|
||||
|
||||
**Created**: 2026-09-03
|
||||
|
||||
**Status**: Draft
|
||||
|
||||
**Input**: User description: "Phase 9 of docs/10-implementation-roadmap.md: Investigation/
|
||||
RootCause/Solution/SolutionImplementation/SolutionVerification/Resolution models and workflows,
|
||||
customer confirmation + reopen flow. Per docs/04-ticketing-and-problem-management.md §3-9 and
|
||||
docs/06-database-schema.md 'Domain: Problem Resolution'."
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - An agent records structured investigation findings (Priority: P1)
|
||||
|
||||
An agent investigating a problem records findings, evidence, and internal notes as a structured
|
||||
record — not a free-text blob buried in a message — with its own status (`open`/`complete`). A
|
||||
problem can have more than one investigation attempt over its lifetime, each preserved, not
|
||||
overwritten.
|
||||
|
||||
**Why this priority**: Everything downstream (root cause, solution, verification) reads from or
|
||||
references an investigation; nothing else in this feature can start without one existing first.
|
||||
|
||||
**Independent Test**: Record an investigation with findings and evidence for a problem; confirm
|
||||
it's retrievable exactly as given, with its own investigator and timestamp.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** an agent records an investigation with findings, **When** it's saved, **Then** it's
|
||||
retrievable with `investigator`, `findings`, `evidence`, `internalNotes`, and `status` exactly
|
||||
as given.
|
||||
2. **Given** a problem already has a completed investigation, **When** a new investigation is
|
||||
started for the same problem (e.g., after a failed verification, User Story 4), **Then** the
|
||||
prior investigation's record is preserved unchanged — a new investigation is its own row, never
|
||||
an overwrite of the earlier one.
|
||||
3. **Given** `internalNotes` on an investigation, **When** any customer-facing view is composed,
|
||||
**Then** that data is never included — internal notes are agent/admin-only, same "never shown
|
||||
to customers" discipline as ticketing's `INTERNAL_NOTE` message type (004 §10).
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - An agent records a root cause, separate from the investigation (Priority: P1)
|
||||
|
||||
Once findings point to a cause, the agent records a root cause as its own record — distinct from
|
||||
the investigation that surfaced it — typed as technical, configuration, external-dependency,
|
||||
business, or a contributing factor.
|
||||
|
||||
**Why this priority**: A solution (User Story 3) is a response to a specific, recorded cause —
|
||||
without one, "solving" a problem has nothing to be checked against.
|
||||
|
||||
**Independent Test**: Record a root cause of a given type for a problem with an investigation
|
||||
already on file; confirm it's retrievable and distinct from the investigation record.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a problem with an investigation on file, **When** an agent records a root cause with
|
||||
a type and description, **Then** it's retrievable as its own record, never merged into the
|
||||
investigation's own fields.
|
||||
2. **Given** a root cause type outside the five documented values, **When** it's submitted,
|
||||
**Then** it's rejected — the type is a closed, validated set, not free text.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - An agent proposes, approves, and implements a solution, each as its own state (Priority: P1)
|
||||
|
||||
A solution moves through distinct states — proposed, approved, implemented — never collapsed into
|
||||
one mutable blob. Implementation is its own record: who implemented it, when, and any notes,
|
||||
kept separate from the proposal itself.
|
||||
|
||||
**Why this priority**: Verification (User Story 4) and resolution (User Story 5) both need a
|
||||
concrete, dated implementation record to verify and resolve against.
|
||||
|
||||
**Independent Test**: Propose a solution, approve it, then record its implementation; confirm all
|
||||
three states are independently visible on the same solution record/its implementation relation.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a root cause on file, **When** an agent proposes a solution, **Then** it's stored
|
||||
with `approved: false` by default.
|
||||
2. **Given** a proposed solution, **When** it's approved, **Then** `approved` becomes `true` —
|
||||
approval is a distinct, explicit action, never implied by implementation happening.
|
||||
3. **Given** an approved solution, **When** an agent records its implementation (notes,
|
||||
implementer, timestamp), **Then** a `SolutionImplementation` record is created, one-to-one
|
||||
with the solution — attempting a second implementation record for the same solution is
|
||||
rejected, not silently overwritten.
|
||||
4. **Given** a solution that has not been approved, **When** an implementation is attempted,
|
||||
**Then** it's rejected — implementation without approval is never allowed.
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - A solution is verified; failure re-opens investigation or escalates (Priority: P2)
|
||||
|
||||
After implementation, the solution is verified by one of several methods (automated check,
|
||||
technical test, customer confirmation, agent confirmation). A successful verification clears the
|
||||
way to resolution (User Story 5). A failed verification either re-opens investigation (a fresh
|
||||
investigation record for the same problem) or escalates the ticket — an agent's explicit choice,
|
||||
not an automatic guess.
|
||||
|
||||
**Why this priority**: Depends on User Story 3 (something implemented to verify). Recording a
|
||||
resolution without ever having verified anything would misrepresent what was actually confirmed.
|
||||
|
||||
**Independent Test**: Verify an implemented solution as failed; confirm no `Resolution` can be
|
||||
recorded from it, and that either a fresh investigation exists or the ticket has been escalated,
|
||||
per the agent's chosen path.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** an implemented solution, **When** it's verified with `result: success`, **Then** a
|
||||
`SolutionVerification` record is created (method, result, evidence, timestamp), one-to-one
|
||||
with the solution.
|
||||
2. **Given** an implemented solution, **When** it's verified with `result: failed`, **Then** no
|
||||
resolution can reference this solution's verification as successful — a failed verification is
|
||||
a real, recorded outcome, not silently discarded.
|
||||
3. **Given** a failed verification and the agent chooses re-investigation, **When** that choice is
|
||||
made, **Then** a new `Investigation` record is created for the same problem (User Story 1's own
|
||||
"each attempt is its own row" rule).
|
||||
4. **Given** a failed verification and the agent chooses escalation instead, **When** that choice
|
||||
is made, **Then** the ticket transitions to `HUMAN_ESCALATION` through 003-ticketing's existing
|
||||
state machine — 007's orchestration re-runs automatically from that transition alone, exactly
|
||||
as it already does for any other route into `HUMAN_ESCALATION`; this feature does not invent a
|
||||
second escalation mechanism alongside 008's.
|
||||
|
||||
---
|
||||
|
||||
### User Story 5 - A resolution is recorded, with configurable customer confirmation or auto-close (Priority: P1)
|
||||
|
||||
Once a solution is verified successful, a `Resolution` record captures the final outcome for the
|
||||
ticket. Depending on configuration, the ticket either waits for explicit customer confirmation
|
||||
before closing, or auto-closes after a configured waiting period with no response.
|
||||
|
||||
**Why this priority**: This is the feature's actual deliverable from the customer's point of
|
||||
view — everything before this is agent-facing work product.
|
||||
|
||||
**Independent Test**: Record a resolution for a ticket with a successfully verified solution;
|
||||
confirm the ticket reaches `RESOLUTION_PENDING_CUSTOMER`, then either an explicit confirmation or
|
||||
the configured waiting period elapsing moves it to `RESOLVED`.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a solution with a successful verification, **When** an agent records a resolution,
|
||||
**Then** a `Resolution` record is created (`outcome`, `resolvedBy`) and the ticket transitions
|
||||
to `RESOLUTION_PENDING_CUSTOMER`.
|
||||
2. **Given** a ticket in `RESOLUTION_PENDING_CUSTOMER`, **When** the customer explicitly confirms,
|
||||
**Then** the ticket transitions to `RESOLVED`.
|
||||
3. **Given** a ticket in `RESOLUTION_PENDING_CUSTOMER` with no customer response, **When** the
|
||||
configured auto-close waiting period elapses, **Then** the ticket transitions to `RESOLVED`
|
||||
automatically — durably, via a background job, never an in-memory timer (Constitution
|
||||
Principle VII, same discipline 008's breach-detection job already established).
|
||||
4. **Given** a `Resolution` is attempted without a successfully verified solution on file,
|
||||
**When** it's attempted, **Then** it's rejected — a resolution must be backed by real,
|
||||
recorded verification, never asserted on its own.
|
||||
|
||||
---
|
||||
|
||||
### User Story 6 - A resolved or closed ticket can be reopened (Priority: P2)
|
||||
|
||||
A customer or agent can reopen a `RESOLVED` or `CLOSED` ticket, which re-enters the appropriate
|
||||
point in the lifecycle rather than starting over from `NEW`.
|
||||
|
||||
**Why this priority**: Depends on User Story 5 (a ticket has to have reached a closeable state
|
||||
before reopening it means anything). Closes the loop 008 explicitly left open ("reopening... may
|
||||
need its own SLA-run-restart decision").
|
||||
|
||||
**Independent Test**: Reopen a `RESOLVED` ticket; confirm it transitions to `REOPENED` and then
|
||||
into an active lifecycle state, and that the prior resolution record remains on file, unaltered.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a `RESOLVED` or `CLOSED` ticket, **When** the customer or an agent reopens it,
|
||||
**Then** the ticket transitions to `REOPENED` and then to `IN_PROGRESS` (003's existing
|
||||
`REOPENED → IN_PROGRESS` transition) — never back to `NEW`.
|
||||
2. **Given** a ticket is reopened, **When** the prior `Resolution` record is checked, **Then** it
|
||||
remains on file exactly as it was — reopening never deletes or mutates history.
|
||||
3. **Given** a ticket already has an SLA run (008) from its original assignment, **When** it's
|
||||
reopened, **Then** no new SLA run is created and the existing one is left exactly as it was
|
||||
(008's own Assumptions: "SLA runs are 1:1 with a ticket's first successful assignment only") —
|
||||
this feature does not retroactively expand that boundary.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- What happens if an agent tries to record a root cause before any investigation exists for the
|
||||
problem? Rejected — a root cause without a preceding investigation has nothing to be grounded
|
||||
in (FR-006).
|
||||
- What happens if a solution is proposed for a problem with no root cause on file? Rejected, same
|
||||
reasoning as above (FR-009).
|
||||
- What happens if two verification attempts are recorded for the same solution? Rejected — like
|
||||
`SolutionImplementation`, `SolutionVerification` is one-to-one with its solution (doc 06's own
|
||||
`@unique` on `solutionId`); a second verification attempt on an already-verified solution is out
|
||||
of scope for this feature (re-verification of a previously-verified solution is not a flow doc
|
||||
04 describes).
|
||||
- What happens to a ticket's messages/attachments/assignment history when it's reopened? Nothing
|
||||
— reopening only affects `Ticket.status`; every other record (007's `Assignment`, 008's
|
||||
`SLARun`, this feature's own `Investigation`/`RootCause`/`Solution`/`Resolution` records) is
|
||||
untouched by the reopen transition itself.
|
||||
- What happens if the configured auto-close waiting period is set to zero or is unconfigured?
|
||||
Zero is a valid configuration (auto-close as soon as the sweep next runs); unconfigured falls
|
||||
back to a system default (Constitution Principle II — configuration over hardcoding, but a
|
||||
default value must exist so the sweep job always has something to compare against).
|
||||
- What happens if a ticket is reopened more than once? Each reopen is its own `REOPENED →
|
||||
IN_PROGRESS` transition — no cap on how many times a ticket can be reopened is introduced by
|
||||
this feature (counting reopens toward an escalation trigger remains 008's already-documented,
|
||||
deliberately deferred `repeated_reopen` trigger type — this feature does not wire it up).
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: The system MUST let an agent record an investigation (investigator, findings,
|
||||
evidence, internal notes, status) for a problem.
|
||||
- **FR-002**: Each investigation MUST be its own durable record — a new investigation for the
|
||||
same problem (e.g., after a failed verification) MUST NOT overwrite a prior one.
|
||||
- **FR-003**: Internal notes on an investigation MUST NEVER be exposed through any
|
||||
customer-facing read path.
|
||||
- **FR-004**: The system MUST let an agent record a root cause (type, description) for a
|
||||
problem, as a record distinct from any investigation.
|
||||
- **FR-005**: A root cause's type MUST be validated against the five documented values
|
||||
(technical, configuration, external_dependency, business, contributing_factor) — never
|
||||
free text.
|
||||
- **FR-006**: Recording a root cause for a problem with no investigation on file MUST be
|
||||
rejected.
|
||||
- **FR-007**: The system MUST let an agent propose a solution for a problem (`approved: false`
|
||||
by default), approve it explicitly, and record its implementation (notes, implementer,
|
||||
timestamp) as a separate, one-to-one record.
|
||||
- **FR-008**: Recording an implementation for a solution that has not been approved MUST be
|
||||
rejected.
|
||||
- **FR-009**: Proposing a solution for a problem with no root cause on file MUST be rejected.
|
||||
- **FR-010**: The system MUST let an agent record a verification (method, result, evidence) for
|
||||
an implemented solution, as a one-to-one record.
|
||||
- **FR-011**: A verification's method MUST be validated against the four documented values
|
||||
(automated, technical_test, customer_confirmation, agent_confirmation).
|
||||
- **FR-012**: A failed verification MUST NOT permit a `Resolution` to be recorded against that
|
||||
solution.
|
||||
- **FR-013**: On a failed verification, the system MUST support either starting a fresh
|
||||
investigation for the same problem (FR-002) or transitioning the ticket to `HUMAN_ESCALATION`
|
||||
(003's existing state machine, triggering 007's existing orchestration subscriber
|
||||
automatically) — the choice between the two is the recording agent's, not automatic.
|
||||
- **FR-014**: The system MUST let an agent record a `Resolution` (outcome, resolvedBy) for a
|
||||
ticket, only when a successfully verified solution exists for its problem — this transitions
|
||||
the ticket to `RESOLUTION_PENDING_CUSTOMER`.
|
||||
- **FR-015**: The system MUST let a customer explicitly confirm a pending resolution, transitioning
|
||||
the ticket to `RESOLVED`.
|
||||
- **FR-016**: The system MUST auto-transition a ticket from `RESOLUTION_PENDING_CUSTOMER` to
|
||||
`RESOLVED` after a configured waiting period with no explicit customer confirmation — detected
|
||||
by a durable background job, never an in-memory timer (Constitution Principle VII).
|
||||
- **FR-017**: The system MUST let a customer or agent reopen a `RESOLVED` or `CLOSED` ticket,
|
||||
transitioning it to `REOPENED` and then `IN_PROGRESS` — never back to `NEW`, and never
|
||||
mutating any prior investigation/root-cause/solution/verification/resolution record.
|
||||
- **FR-018**: Reopening a ticket MUST NOT create a new SLA run (008's existing 1:1-with-first-
|
||||
assignment boundary is unchanged by this feature).
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **Investigation**: A structured, per-attempt record of what an agent found while investigating
|
||||
a problem — findings, evidence, internal notes — never free text buried in a message; a problem
|
||||
can have more than one, each preserved.
|
||||
- **Root Cause**: Why the problem happened, typed and recorded separately from what was found
|
||||
(the investigation).
|
||||
- **Solution**: What's proposed to fix the root cause, moving through proposed → approved states
|
||||
explicitly.
|
||||
- **Solution Implementation**: The one-to-one record of a solution actually being carried out —
|
||||
who, when, and any notes — distinct from the proposal.
|
||||
- **Solution Verification**: The one-to-one record of whether the implementation actually worked,
|
||||
by which method.
|
||||
- **Resolution**: The final, ticket-level outcome — distinct from the solution (what was done)
|
||||
and the verification (whether it worked).
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: 100% of investigation/root-cause/solution/implementation/verification/resolution
|
||||
records, once created, remain retrievable exactly as given — no field silently dropped or
|
||||
overwritten by a later action in the same problem's lifecycle.
|
||||
- **SC-002**: 100% of internal-notes fields are absent from every customer-facing response,
|
||||
verified by a direct comparison of the agent-facing and customer-facing read paths for the same
|
||||
investigation.
|
||||
- **SC-003**: 100% of resolutions recorded without a successfully verified solution on file are
|
||||
rejected.
|
||||
- **SC-004**: 100% of tickets reaching `RESOLUTION_PENDING_CUSTOMER` with no explicit customer
|
||||
confirmation reach `RESOLVED` within one auto-close job cycle of their configured waiting
|
||||
period elapsing.
|
||||
- **SC-005**: 100% of reopened tickets leave every prior investigation/root-cause/solution/
|
||||
verification/resolution record and SLA run untouched.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- **This feature does not build a customer-facing confirmation UI** — "explicit customer
|
||||
confirmation" (FR-015) is an API action a caller (a future customer portal, or 008/010's own
|
||||
future UI work) can invoke; this feature's own scope is the backend transition and the
|
||||
auto-close fallback, not a rendered confirmation page (010 — Agent/Admin UI — is a separate,
|
||||
later roadmap phase).
|
||||
- **Verification-failure escalation reuses 003-ticketing's existing `HUMAN_ESCALATION` state
|
||||
transition and 007's already-automatic orchestration subscriber directly** — it does not create
|
||||
a new `EscalationEvent` through 008's rule-based mechanism, since "solution verification failed"
|
||||
is not one of doc 05 §6's ten escalation trigger types 008 modeled; inventing an eleventh type
|
||||
for a single feature's own internal flow was judged unnecessary scope, not an oversight.
|
||||
Re-escalation through the plain ticket-status transition is exactly what 007 was already built
|
||||
to react to — no new coupling is introduced.
|
||||
- **The auto-close waiting period is a single, system-wide configuration value** (Principle II —
|
||||
configuration over hardcoding), not scoped per product/category the way 008's SLA policies are;
|
||||
doc 04 §9 describes it as "a configured waiting period," not a per-context policy table, and
|
||||
nothing in doc 06's schema defines a per-scope auto-close entity to resolve against.
|
||||
- **`repeated_reopen` (008's already-inert escalation trigger type) is still not wired up by this
|
||||
feature** — reopening increments no counter and triggers no escalation rule; this remains
|
||||
future work exactly as 008's own Assumptions already documented, not something this feature
|
||||
silently expands into.
|
||||
- **A second verification attempt on an already-verified solution is out of scope** — doc 06's
|
||||
`SolutionVerification.solutionId` is `@unique`, meaning at most one verification record per
|
||||
solution; if a first verification fails and the agent chooses re-investigation (FR-013), any
|
||||
new solution that comes out of that fresh investigation cycle gets its own new `Solution` row
|
||||
(User Story 3) with its own verification slot — never a second write to the original one.
|
||||
Reference in New Issue
Block a user