docs(23): capture phase context
This commit is contained in:
parent
8a11a9f331
commit
98c7153a10
2 changed files with 344 additions and 0 deletions
|
|
@ -0,0 +1,246 @@
|
|||
# Phase 23: Classification Disposition + Per-Client Automation Gate - Context
|
||||
|
||||
**Gathered:** 2026-07-16
|
||||
**Status:** Ready for planning
|
||||
|
||||
<domain>
|
||||
## Phase Boundary
|
||||
|
||||
Two related capabilities in the phishing triage pipeline:
|
||||
|
||||
1. **A dedicated "confirmed simulated phish" verdict.** The classifier
|
||||
(`campaign-classifier.ts`) already detects known phishing-simulation
|
||||
vendors (KnowBe4/Breach Secure Now) via sender-domain allowlist and
|
||||
explicitly skips the THREAT tier for them — but the result still lands in
|
||||
the generic `UNWANTED` bucket (the same disposition as run-of-the-mill
|
||||
marketing spam), with the recommended action `warn_user`. This phase adds
|
||||
a distinct 4th verdict with a new, distinct recommended action.
|
||||
|
||||
2. **A per-client automation gate.** With the Autotask webhook now fixed
|
||||
(delivering ticket create/update events again after ~3 months dead), the
|
||||
pipeline's parse/classify/report stages *could* run automatically per
|
||||
report. Today they're always manual (an explicit design limitation from
|
||||
Phase 18 — `parseAndStoreMessage` and `classifyCampaign` are never called
|
||||
by the automatic webhook/cron path). This phase adds an admin page letting
|
||||
an admin choose, per Autotask company, which of these stages run
|
||||
automatically instead of requiring the existing manual triggers.
|
||||
|
||||
Does NOT cover: changing the classifier's detection logic itself (the
|
||||
KnowBe4/BSN sender-domain allowlist already exists and works — this phase
|
||||
only changes what verdict/action it maps to), changing Phase 20's remediation
|
||||
approval model for real threats (quarantine/block/etc. always require manual
|
||||
approval, regardless of this phase's automation gate), or re-litigating the
|
||||
webhook fix (already shipped as quick task 260716-n46 in this same session).
|
||||
|
||||
</domain>
|
||||
|
||||
<decisions>
|
||||
## Implementation Decisions
|
||||
|
||||
### New Verdict: User Acknowledgment
|
||||
- **D-01:** Add a 4th `Verdict` value (working name `USER_AWARENESS` — exact
|
||||
string is Claude's discretion, pick something that reads clearly in
|
||||
`StatusBadge`/reporting) for campaigns where the classifier's own reasoning
|
||||
already shows a phishing-simulation-vendor sender-domain match. This is
|
||||
additive to the existing `SPAM | UNWANTED | THREAT` union, not a
|
||||
replacement.
|
||||
- **D-02:** This verdict maps to a NEW recommended action, `acknowledge_user`
|
||||
(not `warn_user`) — a professional message thanking the employee for
|
||||
reporting it and reinforcing that their vigilance helps keep the company
|
||||
secure. Exact copy is Claude's discretion; tone should be genuinely
|
||||
appreciative, not templated-sounding.
|
||||
- **D-03:** `acknowledge_user` delivers as a **customer-visible (Publish=true)
|
||||
Autotask ticket note** — not an internal-only note like Phase 21's existing
|
||||
triage-note, and not a separate email. Reuses the existing `TicketNotes`
|
||||
write path from `triage-note-service.ts`, with the visibility flag flipped
|
||||
for this specific action type so the reporting employee actually sees it
|
||||
(via their normal ticket notification/portal).
|
||||
- **D-04:** `acknowledge_user` is exempt from Phase 20's proposed-only /
|
||||
manual-approval model — for companies with the automation gate's
|
||||
"report-to-ticket" stage enabled, it posts automatically without an
|
||||
operator clicking Approve first. This is a deliberate, narrow carve-out:
|
||||
it applies ONLY to `acknowledge_user` (a thank-you message, not a security
|
||||
action). Every other recommended action (quarantine, block sender,
|
||||
warn_user, etc.) always requires manual approval regardless of the
|
||||
automation gate, unchanged from Phase 20.
|
||||
|
||||
### Automation Gate: Granularity and Defaults
|
||||
- **D-05:** Three independent per-company toggles, not one master switch:
|
||||
**parse**, **classify**, **report-to-ticket**. A company can, e.g., have
|
||||
auto-parse+classify enabled but auto-report disabled (an operator reviews
|
||||
before anything reaches the client's ticket).
|
||||
- **D-06:** Default state for a company with no explicit row is **all three
|
||||
OFF** (opt-in, not opt-out). A client only gets automatic pipeline
|
||||
execution once someone deliberately enables it for them — mirrors Phase
|
||||
20's "proposed-only by default" safety posture. This also means: even with
|
||||
the webhook now delivering ticket-create events for every company, nothing
|
||||
changes in current pipeline behavior until an admin opts a company in via
|
||||
this new page.
|
||||
- **D-07 (derived, not separately asked):** Detection + Tier-3 grouping
|
||||
(already automatic via the webhook, unconditionally, for every company —
|
||||
fixed in quick task 260716-n46) are UNAFFECTED by this gate. The gate only
|
||||
ever controls the three previously-manual-only stages (parse, classify,
|
||||
report). Detection/grouping are non-destructive (just flag + bucket into a
|
||||
campaign) and were never gated behind per-company consent even before this
|
||||
phase — no reason to add friction there.
|
||||
|
||||
### Automation Gate: Admin Surface
|
||||
- **D-08:** New dedicated page at `/admin/phishing-automation`, `admin` role
|
||||
(not super-admin-restricted) — consistent with other `/admin/*` pages.
|
||||
Structurally mirrors the existing `/admin/client-scope` page: a searchable/
|
||||
filterable company table (reuse `components/admin/DataTable.tsx`), one row
|
||||
per company, with the three stage toggles as `Switch` components per row
|
||||
(see Reusable Assets below for the exact analog).
|
||||
|
||||
### Claude's Discretion
|
||||
- Exact new verdict string value (`USER_AWARENESS` vs. alternatives) and its
|
||||
`StatusBadge` color/variant.
|
||||
- Exact `acknowledge_user` message copy (tone direction given: professional,
|
||||
genuinely appreciative — see D-02).
|
||||
- Schema shape for the automation-gate settings (new table keyed by
|
||||
`company_id` with three boolean columns vs. some other normalization) —
|
||||
whatever is cleanest given `company_scope`'s existing precedent (migration
|
||||
082: absent row = default, explicit row = override).
|
||||
- Whether the automatic parse/classify/report pipeline runs synchronously
|
||||
inline in the webhook handler (mirroring today's automatic detect+group
|
||||
call in `triggerPhishingDetection()`) or is queued for a worker to pick up
|
||||
— an implementation detail, not a user-facing behavior choice, as long as
|
||||
it eventually runs without a human clicking a button.
|
||||
- Audit/logging of automation-gate toggle changes (who/when) — reasonable to
|
||||
add given `integration_settings`' existing `disabled_by`/`disabled_at`
|
||||
pattern, but not something the user was asked about explicitly.
|
||||
|
||||
</decisions>
|
||||
|
||||
<canonical_refs>
|
||||
## Canonical References
|
||||
|
||||
**Downstream agents MUST read these before planning or implementing.**
|
||||
|
||||
### Existing pipeline stages this phase gates
|
||||
- `lib/services/campaign-classifier.ts` — `Verdict` type (`SPAM | UNWANTED |
|
||||
THREAT`), `mapVerdictToActions()`, and the existing KnowBe4/Breach Secure
|
||||
Now sender-domain-allowlist detection that already skips the THREAT tier
|
||||
(search for "phishing-simulation vendor allowlist" in its reasoning
|
||||
strings) — this phase changes what verdict/action that detection maps to,
|
||||
not the detection itself.
|
||||
- `lib/services/phishing-eml-service.ts` — `parseAndStoreMessage()`, the
|
||||
"parse" stage.
|
||||
- `lib/services/campaign-grouping-service.ts` — module doc-comment's
|
||||
documented D-07 limitation: `parseAndStoreMessage` and classification are
|
||||
"not wired into the automatic webhook/cron path" — this phase is what
|
||||
wires them in, per-company, behind the new gate.
|
||||
- `lib/services/webhook-service.ts` — `triggerPhishingDetection()`, the
|
||||
existing automatic detect+Tier-3-group call fired on every `Ticket` webhook
|
||||
create event (fixed this session — see quick task
|
||||
`.planning/quick/260716-n46-fix-mimecast-blast-radius-date-window-fu/`).
|
||||
The new automatic parse/classify/report calls should follow this same
|
||||
call site's shape (read the ticket row back from Postgres, run the next
|
||||
stage, never block the webhook response).
|
||||
- `lib/services/triage-note-service.ts` — `generateAndPostTriageNote()`, the
|
||||
existing internal-note writer this phase's `acknowledge_user` action reuses
|
||||
with a flipped visibility flag; also the "report-to-ticket" automation
|
||||
stage's existing manual equivalent.
|
||||
- `app/api/phishing/campaigns/[id]/classify/route.ts` — the only existing
|
||||
trigger of `classifyCampaign`; the new automatic "classify" stage should
|
||||
call the same underlying service function this route calls, not duplicate
|
||||
classification logic.
|
||||
|
||||
### Automation-gate UI/API precedent
|
||||
- `app/admin/client-scope/page.tsx` — the exact UI pattern to mirror: company
|
||||
table with search/type-filter + `Switch` per row, backed by
|
||||
`app/api/admin/company-scope/route.ts`.
|
||||
- `migrations/082_company_scope.sql` — the opt-out-table schema precedent
|
||||
(`company_id` + boolean, absent row = default true, explicit row =
|
||||
override) to adapt for this phase's opt-IN, three-boolean shape.
|
||||
- `migrations/081_*.sql` (`integration_settings` table) — the
|
||||
`disabled_by`/`disabled_at`/`disabled_reason` audit-column precedent, if
|
||||
audit logging is added per Claude's Discretion above.
|
||||
|
||||
### Phase 20 safety model this phase narrowly carves out of
|
||||
- `.planning/phases/20-remediation-approval-audit-safety/` (SUMMARY/PLAN
|
||||
files) — the "proposed-only, human-approved" remediation model.
|
||||
`acknowledge_user` is the ONLY action exempted from manual approval by this
|
||||
phase (D-04); every other action type is unaffected.
|
||||
|
||||
### Prior phase context carried forward
|
||||
- `.planning/phases/22-approval-ui-livelink-addressable-campaign-review-and-approve/22-CONTEXT.md`
|
||||
— D-06's `hasPermission()` client-side gating pattern (reuse for the new
|
||||
admin page's action buttons if any client-side gating is needed beyond the
|
||||
page-level `admin` role check).
|
||||
|
||||
</canonical_refs>
|
||||
|
||||
<code_context>
|
||||
## Existing Code Insights
|
||||
|
||||
### Reusable Assets
|
||||
- `app/admin/client-scope/page.tsx` + `app/api/admin/company-scope/route.ts`
|
||||
— direct structural template for the new automation-gate page (table +
|
||||
search/filter + per-row toggle(s), just 3 Switches instead of 1).
|
||||
- `components/admin/DataTable.tsx` — table wrapper already used by
|
||||
`client-scope` and other admin pages.
|
||||
- `lib/services/triage-note-service.ts` — reuse its `TicketNotes` write call
|
||||
shape for `acknowledge_user`, just with the publish/visibility flag
|
||||
flipped.
|
||||
- `lib/permissions.ts` / `requirePermission()` — existing admin-role gate
|
||||
pattern for the new page's API routes.
|
||||
|
||||
### Established Patterns
|
||||
- Opt-in/opt-out settings-table pattern already exists twice
|
||||
(`company_scope` for analytics, `integration_settings` for integration
|
||||
toggles) — this phase's automation-gate table is a third instance of the
|
||||
same pattern, just with 3 booleans instead of 1 and opt-in instead of
|
||||
opt-out defaults.
|
||||
- "Absent row = default behavior, explicit row = override" is the
|
||||
established convention for these settings tables — follow it rather than
|
||||
requiring a row to exist for every company up front.
|
||||
|
||||
### Integration Points
|
||||
- New automatic parse/classify/report calls plug into
|
||||
`webhookService`'s existing `triggerPhishingDetection()` call site (or a
|
||||
sibling method called from the same place) — after detection+grouping
|
||||
succeeds, check the grouped campaign's company against the new gate table
|
||||
before calling `parseAndStoreMessage`/`classifyCampaign`/
|
||||
`generateAndPostTriageNote`.
|
||||
- `ClassificationCard` (Phase 22) needs to render the new verdict with its
|
||||
own `StatusBadge` variant/color, distinct from `UNWANTED`'s existing
|
||||
styling.
|
||||
- `ActionAreaCard` (Phase 22) needs to handle `acknowledge_user` as a
|
||||
recommended-action checkbox like today's other action types, for the
|
||||
manual path (companies without report-to-ticket automation enabled still
|
||||
see it as a normal proposed action an operator approves).
|
||||
|
||||
</code_context>
|
||||
|
||||
<specifics>
|
||||
## Specific Ideas
|
||||
|
||||
- The `acknowledge_user` message should read as a genuine thank-you, not a
|
||||
templated compliance notice — explicit framing from discussion: "a
|
||||
professional message letting them know we appreciate their attention in
|
||||
keeping the company secure."
|
||||
- This phase's motivating example: ticket 699415 (Seubert & Associates,
|
||||
"Phishing Report - direccion@it-support.care - Attention Please"),
|
||||
correctly classified `UNWANTED` with the BSN-allowlist reasoning already
|
||||
present, confidence display bug already fixed separately (quick task
|
||||
260716-pgr) — but the disposition itself is what this phase corrects.
|
||||
|
||||
</specifics>
|
||||
|
||||
<deferred>
|
||||
## Deferred Ideas
|
||||
|
||||
None — discussion stayed within phase scope. (The webhook fix and the
|
||||
confidence display bug that surfaced during the same investigation were
|
||||
already resolved as separate quick tasks, not folded into this phase.)
|
||||
|
||||
### Reviewed Todos (not folded)
|
||||
None — no pending todos matched this phase.
|
||||
|
||||
</deferred>
|
||||
|
||||
---
|
||||
|
||||
*Phase: 23-classification-disposition-per-client-automation-gate*
|
||||
*Context gathered: 2026-07-16*
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
# Phase 23: Classification Disposition + Per-Client Automation Gate - Discussion Log
|
||||
|
||||
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
|
||||
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
|
||||
|
||||
**Date:** 2026-07-16
|
||||
**Phase:** 23-classification-disposition-per-client-automation-gate
|
||||
**Areas discussed:** Gate granularity, Default state, Verdict behavior, Gate page location, Acknowledge-user delivery path, Auto-approval carve-out
|
||||
|
||||
---
|
||||
|
||||
## Gate granularity
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| One master toggle per company | Single on/off switch controlling parse+classify+report together | |
|
||||
| Separate toggles per stage | Three independent switches (parse / classify / report-to-ticket) per company | ✓ |
|
||||
|
||||
**User's choice:** Separate toggles per stage.
|
||||
**Notes:** More flexible than a single switch — a company can have auto-parse+classify without auto-report, keeping a human review point before anything reaches the client's ticket.
|
||||
|
||||
---
|
||||
|
||||
## Default state
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Off by default, opt-in per client | A client only gets automation once explicitly enabled | ✓ |
|
||||
| On by default, opt-out per client | Every client automated immediately unless explicitly disabled | |
|
||||
|
||||
**User's choice:** Off by default, opt-in per client.
|
||||
**Notes:** Matches Phase 20's "proposed-only" safety posture — nothing client-facing happens automatically without deliberate enablement.
|
||||
|
||||
---
|
||||
|
||||
## Verdict behavior
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| New 4th verdict, same warn_user action | New disposition label, unchanged downstream action | |
|
||||
| New verdict + no action needed | New disposition, empty/no-op recommended action | |
|
||||
| New 4th verdict, new acknowledge_user action | New disposition + new action: professional thank-you message | ✓ (user's own answer, not a listed option) |
|
||||
|
||||
**User's choice:** New 4th verdict with a new `acknowledge_user` recommended action — "a professional message letting them know we appreciate their attention in keeping the company secure."
|
||||
**Notes:** Neither preset option captured this — the user wanted active positive reinforcement, not just a relabeled no-op. Became D-01/D-02 in CONTEXT.md.
|
||||
|
||||
---
|
||||
|
||||
## Acknowledge-user delivery path
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Publish-visible Autotask ticket note | Customer-visible note via existing TicketNotes write path, visibility flag flipped | ✓ |
|
||||
| Direct reply-email to the reporter | New delivery mechanism, independent of the ticket | |
|
||||
|
||||
**User's choice:** Publish-visible Autotask ticket note.
|
||||
**Notes:** Reuses Phase 21's existing internal-note write path, just customer-visible instead of internal-only, so the reporting employee sees it via their normal ticket notification/portal.
|
||||
|
||||
---
|
||||
|
||||
## Auto-approval carve-out
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Skip approval for acknowledge_user only | Thank-you message auto-posts for opted-in companies; all other actions (quarantine, block, warn_user) still always require manual approval | ✓ |
|
||||
| Still require manual approval for everything | Automation gate only controls parse+classify; report-to-ticket still needs an explicit Approve click | |
|
||||
|
||||
**User's choice:** Skip approval for acknowledge_user only.
|
||||
**Notes:** A narrow, explicit carve-out from Phase 20's proposed-only model — applies only to this one non-security, non-destructive action type.
|
||||
|
||||
---
|
||||
|
||||
## Gate page location
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| New /admin/phishing-automation page, admin role | Dedicated page mirroring /admin/client-scope's exact pattern | ✓ |
|
||||
| Same page, super-admin only | Same UI, gated to super-admin instead | |
|
||||
|
||||
**User's choice:** New /admin/phishing-automation page, admin role.
|
||||
**Notes:** Consistent with other /admin/* pages — this is a service-delivery toggle, not billing/security config.
|
||||
|
||||
---
|
||||
|
||||
## Claude's Discretion
|
||||
|
||||
- Exact new verdict string value and its StatusBadge color/variant.
|
||||
- Exact acknowledge_user message copy (tone direction given, wording open).
|
||||
- Automation-gate settings table schema (adapt company_scope's precedent to 3 booleans, opt-in).
|
||||
- Whether automatic pipeline stages run inline in the webhook handler or via a queued worker.
|
||||
- Whether to add audit logging (who/when) for gate toggle changes, per the integration_settings precedent.
|
||||
|
||||
## Deferred Ideas
|
||||
|
||||
None — discussion stayed within phase scope. The webhook fix and the confidence
|
||||
display bug that surfaced during the same investigation were resolved as
|
||||
separate quick tasks (260716-n46, 260716-pgr) prior to this discussion, not
|
||||
folded into this phase.
|
||||
Loading…
Add table
Add a link
Reference in a new issue