docs(23-05): complete gated automation pipeline plan
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6RuWdiUiXrPK6FLBHjtpY
This commit is contained in:
parent
e1193bf476
commit
7869e0bcfd
2 changed files with 119 additions and 0 deletions
|
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
phase: 23-classification-disposition-per-client-automation-gate
|
||||
plan: 05
|
||||
subsystem: phishing-triage-automation
|
||||
tags: [webhook, phishing, postgres, vitest, autotask, gate-pattern]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 23-01
|
||||
provides: "USER_AWARENESS verdict on Verdict union, classifyCampaign, generateAndPostAcknowledgment (acknowledge_user note writer)"
|
||||
- phase: 23-03
|
||||
provides: "phishing_automation_gate table (migration 100) + admin CRUD routes for per-company auto_parse/auto_classify/auto_report toggles"
|
||||
provides:
|
||||
- "getCompanyAutomationGate(companyId) reusable COALESCE-false reader"
|
||||
- "Automatic parse -> classify -> acknowledge_user pipeline wired into the live Autotask webhook, gated per-company"
|
||||
affects: [23-remaining-plans, phishing-triage-runbook]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Per-company opt-in settings reader (COALESCE(..., false), absent row = all-false) as a standalone testable module, mirroring the admin route's LEFT JOIN pattern but scoped to a single company_id"
|
||||
- "Gated webhook stage chain: each automation stage wrapped in its own try/catch so a stage failure logs-and-continues without blocking the fire-and-forget webhook response or aborting later stages"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- lib/services/phishing-automation-gate.ts
|
||||
- lib/services/phishing-automation-gate.test.ts
|
||||
modified:
|
||||
- lib/services/webhook-service.ts
|
||||
|
||||
key-decisions:
|
||||
- "auto_report's automatic behavior is narrowly scoped to generateAndPostAcknowledgment for USER_AWARENESS verdicts only — no other action/verdict is ever auto-posted or auto-approved (D-04 carve-out, T-23-08)"
|
||||
- "When auto_report is enabled but auto_classify did not run in the same pass (or failed), the current verdict is read from the most recent classifications row for the campaign rather than re-running classification"
|
||||
- "Detection + grouping remain unconditional for every company regardless of gate state (D-07) — only the three post-grouping stages are gated"
|
||||
|
||||
patterns-established:
|
||||
- "runGatedPhishingStages(input) as the single gated-stage entry point, called only when groupReportIntoCampaign resolves a campaignId"
|
||||
|
||||
requirements-completed: [AUTOGATE-03]
|
||||
|
||||
# Metrics
|
||||
duration: 15min
|
||||
completed: 2026-07-16
|
||||
---
|
||||
|
||||
# Phase 23 Plan 05: Wire Gated Automation Pipeline Into Webhook Summary
|
||||
|
||||
**Adds a tested `getCompanyAutomationGate` reader and wires the opted-in parse -> classify -> acknowledge_user chain into the live Autotask webhook, with detection/grouping staying always-on and every other remediation action staying manual-approval-gated.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** ~15 min
|
||||
- **Started:** 2026-07-16T23:31:00Z (approx)
|
||||
- **Completed:** 2026-07-16T23:46:41Z
|
||||
- **Tasks:** 2/2 completed
|
||||
- **Files modified:** 3 (2 created, 1 modified)
|
||||
|
||||
## Accomplishments
|
||||
- `getCompanyAutomationGate(companyId)` reusable reader: absent row / null / NaN companyId all resolve to all-false without throwing; present row maps snake_case -> camelCase.
|
||||
- `triggerPhishingDetection` now captures `groupReportIntoCampaign`'s result and, when a campaign exists, runs the new `runGatedPhishingStages` method — automatically parsing, classifying, and (only for USER_AWARENESS) posting the acknowledge_user note for opted-in companies, entirely within the existing fire-and-forget call site.
|
||||
- Detection and grouping remain unconditional (D-07); no other verdict/action (block_sender, purge_message, warn_user, reset_password, etc.) is ever auto-posted or auto-approved by this change.
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Create getCompanyAutomationGate reader + tests** - `0d7974c` (test, RED) -> `e0f22f2` (feat, GREEN)
|
||||
2. **Task 2: Wire gated parse->classify->acknowledge chain into triggerPhishingDetection** - `e1193bf` (feat)
|
||||
|
||||
_TDD gate sequence for Task 1 confirmed in git log: test commit `0d7974c` precedes feat commit `e0f22f2`._
|
||||
|
||||
## Files Created/Modified
|
||||
- `lib/services/phishing-automation-gate.ts` - `getCompanyAutomationGate(companyId)`: COALESCE(..., false)-backed per-company gate reader, never throws.
|
||||
- `lib/services/phishing-automation-gate.test.ts` - 4 vitest cases: absent row, present row mapping, null companyId, NaN companyId.
|
||||
- `lib/services/webhook-service.ts` - `triggerPhishingDetection` now captures the grouping result and calls new private `runGatedPhishingStages`, which reads the gate and conditionally runs `parseAndStoreMessage`, `classifyCampaign`, and `generateAndPostAcknowledgment` (guarded by `verdict === 'USER_AWARENESS'`), each in its own try/catch.
|
||||
|
||||
## Decisions Made
|
||||
- Verdict-for-report lookup: when `auto_classify` didn't run in the same pass (either disabled or its try/catch caught an error), `auto_report`'s USER_AWARENESS check falls back to `SELECT verdict FROM classifications WHERE campaign_id = $1 ORDER BY created_at DESC LIMIT 1` rather than skipping the report stage entirely — this lets a company with only `auto_report` enabled (classification done via the existing manual route) still get the automatic acknowledge_user post once a human/prior automated pass has classified the campaign as USER_AWARENESS.
|
||||
- Kept `runGatedPhishingStages` as a new private method (not inlined into `triggerPhishingDetection`) to keep the always-on detect+group logic visually and structurally separate from the gated stages, per the plan's D-07 emphasis.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written. Both tasks matched the plan's `<action>` and interface contracts (`ParseAndStoreResult`, `ClassifyResult.verdict`, `TriageNoteResult`, `GroupReportResult`) exactly as they already existed on disk from plans 23-01 and 23-03.
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None.
|
||||
|
||||
## Threat Flags
|
||||
|
||||
None — this plan's threat model (T-23-08 through T-23-11) was fully addressed as designed; no new unmodeled surface was introduced. `runGatedPhishingStages` adds no new inbound endpoint, only conditional internal calls to existing, already-reviewed service functions.
|
||||
|
||||
## Verification
|
||||
|
||||
- `npx vitest run lib/services/phishing-automation-gate.test.ts` — 4/4 passed.
|
||||
- `npx tsc --noEmit --pretty` — clean, no errors.
|
||||
- Full `npx vitest run` — 434 passed, 2 failed. The 2 failures are pre-existing and unrelated (`lib/services/analyzer/itglue-search.test.ts`, files never touched by this plan) — logged to `.planning/phases/23-classification-disposition-per-client-automation-gate/deferred-items.md` per the scope-boundary rule rather than fixed here.
|
||||
- Acceptance-criteria greps for Task 2 all pass: `getCompanyAutomationGate` called with `companyId` (the ticket's `company_id`), `USER_AWARENESS` guards the `generateAndPostAcknowledgment` call, no auto-call to approve/remediate/block/purge/warn_user services was added, `detectPhishingTicket`/`groupReportIntoCampaign` remain unconditional, and each of the three gated stages has its own try/catch.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- FOUND: lib/services/phishing-automation-gate.ts
|
||||
- FOUND: lib/services/phishing-automation-gate.test.ts
|
||||
- FOUND: lib/services/webhook-service.ts (modified)
|
||||
- FOUND commit 0d7974c
|
||||
- FOUND commit e0f22f2
|
||||
- FOUND commit e1193bf
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# Deferred Items — Phase 23
|
||||
|
||||
## Pre-existing test failures (out of scope for 23-05)
|
||||
|
||||
`lib/services/analyzer/itglue-search.test.ts` has 2 pre-existing failures
|
||||
(`tolerates per-call failures` test cases) unrelated to plan 23-05's changes.
|
||||
Plan 23-05 only touched `lib/services/phishing-automation-gate.ts`,
|
||||
`lib/services/phishing-automation-gate.test.ts`, and
|
||||
`lib/services/webhook-service.ts` — no analyzer/itglue files were modified.
|
||||
Full suite: `434 passed, 2 failed` both in this one unrelated file. Logged
|
||||
per SCOPE BOUNDARY rule — not fixed here.
|
||||
Loading…
Add table
Add a link
Reference in a new issue