docs(22-01): complete Wave 0 pure-logic extraction plan
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6RuWdiUiXrPK6FLBHjtpY
This commit is contained in:
parent
d30a49f644
commit
96507dc2c6
2 changed files with 136 additions and 0 deletions
|
|
@ -0,0 +1,120 @@
|
|||
---
|
||||
phase: 22-approval-ui-livelink-addressable-campaign-review-and-approve
|
||||
plan: 01
|
||||
subsystem: api
|
||||
tags: [vitest, tdd, postgres, phishing-triage, pure-functions]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 19-phishing-triage-classification-engine
|
||||
provides: campaign-classifier.ts's mapVerdictToActions 7-action vocabulary and postgresClient/vi.mock testing idiom
|
||||
- phase: 20-remediation-approval-audit-safety
|
||||
provides: remediation-service.ts's ApproveActionInput shape and phishing-audit.ts's canonical event_type values
|
||||
provides:
|
||||
- resolveTicketToCampaign(ticketId) — pure ticket->campaign lookup service
|
||||
- deriveDefaultParams(actionType, evidence) — 7-action-type default-param derivation
|
||||
- mergeTimeline(reports, classifications, auditEvents) — chronological 3-source merge
|
||||
affects: [22-02-ticket-campaign-route, 22-04-action-area-card, 22-05-timeline-card]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Pure lib/services/*.ts extraction for route/component logic that needs vitest coverage (test.include is lib/**/*.test.ts only)"
|
||||
- "vi.mock('./postgres-client', () => ({ postgresClient: { query: ... } })) factory-mock idiom (mirrors campaign-classifier.test.ts)"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- lib/services/phishing-ticket-resolver.ts
|
||||
- lib/services/phishing-ticket-resolver.test.ts
|
||||
- lib/services/remediation-default-params.ts
|
||||
- lib/services/remediation-default-params.test.ts
|
||||
- lib/services/phishing-timeline.ts
|
||||
- lib/services/phishing-timeline.test.ts
|
||||
modified: []
|
||||
|
||||
key-decisions:
|
||||
- "Used named import `{ postgresClient }` from './postgres-client' (matches the sibling files' actual convention — campaign-classifier.ts, remediation-service.ts, phishing-audit.ts — and the PATTERNS.md code snippet), not the plan action text's parenthetical 'default import' gloss, since the vi.mock factory only provides a named `postgresClient` export and a default-import call site would not be mocked."
|
||||
- "mergeTimeline's report/classification/audit source shapes use camelCase `createdAt` fields (not snake_case `created_at`) since the read_first note specifies these consume the already-transformed camelCase API response shapes from app/api/phishing/campaigns/[id]/route.ts."
|
||||
|
||||
patterns-established:
|
||||
- "Pattern: exhaustive switch with `default: return {}` for extensible action-type-keyed pure derivations (mirrors mapVerdictToActions)"
|
||||
- "Pattern: discriminated union + fixed KIND_PRIORITY map for stable multi-source chronological merges"
|
||||
|
||||
requirements-completed: [REVIEW-01, REVIEW-02, REVIEW-04]
|
||||
|
||||
# Metrics
|
||||
duration: 12min
|
||||
completed: 2026-07-16
|
||||
---
|
||||
|
||||
# Phase 22 Plan 01: Wave 0 Pure-Logic Extraction Summary
|
||||
|
||||
**Three pure `lib/services/*.ts` modules (ticket->campaign resolver, 7-action-type default-param derivation, 3-source timeline merge) extracted and unit-tested under vitest, unblocking the route/component work in plans 02/04/05.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 12 min
|
||||
- **Started:** 2026-07-16T18:17:00Z
|
||||
- **Completed:** 2026-07-16T18:29:00Z
|
||||
- **Tasks:** 3 completed
|
||||
- **Files modified:** 6 (all new)
|
||||
|
||||
## Accomplishments
|
||||
- `resolveTicketToCampaign(ticketId)` covers all three resolution states (no report / ungrouped / grouped) via a single parameterized `reports` lookup
|
||||
- `deriveDefaultParams(actionType, evidence)` implements the exact 7-action-type default-params table from the UI-SPEC, with a safe `{}` fallback for unknown/future action types
|
||||
- `mergeTimeline(reports, classifications, auditEvents)` produces a single ascending-chronological array with a discriminated `TimelineEntry` union and a deterministic tie-break order
|
||||
- All 3 modules are pure or DB-only (no `NextResponse`/`requirePermission` in any of them) — route-free per the plan's design intent
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed via full TDD RED/GREEN pairs:
|
||||
|
||||
1. **Task 1: phishing-ticket-resolver.ts + test** — `20b1e1b` (test), `e619321` (feat)
|
||||
2. **Task 2: remediation-default-params.ts + test** — `c64a905` (test), `86cffc4` (feat)
|
||||
3. **Task 3: phishing-timeline.ts + test (server-merge)** — `37f6657` (test), `d30a49f` (feat)
|
||||
|
||||
**Plan metadata:** (this commit)
|
||||
|
||||
## Files Created/Modified
|
||||
- `lib/services/phishing-ticket-resolver.ts` - `resolveTicketToCampaign(ticketId)`, parameterized `reports` lookup
|
||||
- `lib/services/phishing-ticket-resolver.test.ts` - 4 tests covering the 3 resolution states + query-shape assertion
|
||||
- `lib/services/remediation-default-params.ts` - `deriveDefaultParams(actionType, evidence)`, exhaustive switch over 7 action types + fallback
|
||||
- `lib/services/remediation-default-params.test.ts` - 9 tests covering all 7 known types, unknown fallback, and null-evidence defaults
|
||||
- `lib/services/phishing-timeline.ts` - `mergeTimeline(reports, classifications, auditEvents)`, `TimelineEntry` discriminated union
|
||||
- `lib/services/phishing-timeline.test.ts` - 4 tests covering sort order, length invariant, per-variant fields, and tie-break stability
|
||||
|
||||
## Decisions Made
|
||||
- Named import for `postgresClient` (not the plan text's literal "default import" parenthetical) — see `key-decisions` above; verified against all 3 sibling files (`campaign-classifier.ts`, `remediation-service.ts`, `phishing-audit.ts`) and the working `vi.mock` test pattern.
|
||||
- `mergeTimeline` inputs are camelCase (`createdAt`, `reportId`, `ticketNumber`, `companyName`, `verdict`, `confidence`, `eventType`, `actor`, `payload`) since this function consumes the campaign-detail route's already-transformed response shape, not raw DB rows.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written, with one clarifying correction to an internal inconsistency in the plan text (see Decisions Made: named vs. default import) resolved in favor of the working, testable convention already established in this phase's sibling files.
|
||||
|
||||
## Issues Encountered
|
||||
None - all three RED phases confirmed failing before implementation (module-not-found), all three GREEN phases passed on first implementation attempt.
|
||||
|
||||
## TDD Gate Compliance
|
||||
|
||||
All three tasks followed the full RED -> GREEN cycle with separate commits:
|
||||
- Task 1: `test(22-01)` at `20b1e1b` -> `feat(22-01)` at `e619321`
|
||||
- Task 2: `test(22-01)` at `c64a905` -> `feat(22-01)` at `86cffc4`
|
||||
- Task 3: `test(22-01)` at `37f6657` -> `feat(22-01)` at `d30a49f`
|
||||
|
||||
No REFACTOR commits were needed — each GREEN implementation passed cleanly without follow-up cleanup.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- Plan 02 (ticket->campaign resolver route) can now call `resolveTicketToCampaign` directly — the route becomes a thin `requirePermission` + param-parse + call wrapper per PATTERNS.md.
|
||||
- Plans 04/05 (Action Area Card, Timeline Card) have a tested `deriveDefaultParams`/`mergeTimeline` to call from their respective routes/components (or the extended `campaigns/[id]` route, per the server-merge decision).
|
||||
- Full test suite: 411/413 passing. The 2 failures are pre-existing, unrelated `lib/services/analyzer/itglue-search.test.ts` failures (untouched by this plan) — logged in `.planning/phases/22-approval-ui-livelink-addressable-campaign-review-and-approve/deferred-items.md`, out of scope per the plan's file list.
|
||||
- `npx tsc --noEmit --pretty` is clean.
|
||||
|
||||
---
|
||||
*Phase: 22-approval-ui-livelink-addressable-campaign-review-and-approve*
|
||||
*Completed: 2026-07-16*
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# Deferred Items — Phase 22
|
||||
|
||||
Pre-existing failures/warnings discovered during execution but out of scope
|
||||
for the current plan (not touched by this plan's files, not caused by this
|
||||
plan's changes).
|
||||
|
||||
## Plan 01
|
||||
|
||||
- `lib/services/analyzer/itglue-search.test.ts` — 2 pre-existing failing
|
||||
tests (`itglueSearch > tolerates per-call failures ...`, doc count
|
||||
mismatches). Unrelated to phishing-ticket-resolver /
|
||||
remediation-default-params / phishing-timeline (this plan's files). Not
|
||||
modified by any commit in this plan. Confirmed present before this plan's
|
||||
changes (file untouched in `git diff`). Full-suite run: `2 failed | 411
|
||||
passed (413)` with only these 2 pre-existing failures — all other tests,
|
||||
including the 3 new files added by this plan, are green.
|
||||
Loading…
Add table
Add a link
Reference in a new issue