wulf-pulse/.planning/quick/260721-mmf-fix-mimecast-blast-radius-scope/260721-mmf-SUMMARY.md

5.1 KiB

phase plan subsystem tags key-decisions status
quick-260721-mmf 01 mimecast-blast-radius
mimecast
phishing
blast-radius
bugfix
Dropped `to`/`recipient` from both fan-out calls entirely rather than making them optional-but-still-passed — Mimecast's client already treats both params as optional, so omitting them is the minimal change that broadens scope without touching BlastRadiusInput or the client contract
Kept domainsMatch(h.from, input.sender) as the sole scoping mechanism for held rows (T-17-01) since getHeldMessages has no server-side sender filter — unchanged from the prior fix in 260718-7v8
recipient stays a required BlastRadiusInput field and is still forced into perRecipientMap as 'unknown' when no row matches it, preserving the reporter-always-represented guarantee
complete

Quick Task 260721-mmf: Fix Mimecast blast-radius query scope

One-liner: Removed the accidental single-recipient scoping (to/recipient params) from both Mimecast fan-out calls in getBlastRadius(), so blast-radius counts and perRecipient now reflect every recipient of a reported phishing campaign across the tenant, not just the original reporter's mailbox.

What was done

Task 1 — Broaden the fan-out query (lib/services/mimecast-blast-radius.ts, commit 58202e0)

  • Removed to: input.recipient from the client.searchDeliveredMessages({...}) call — now passes only from: input.sender, subject: input.subject, start: startStr, end: endStr.
  • Removed recipient: input.recipient from the client.getHeldMessages({...}) call — now passes only start: startStr, end: endStr.
  • Left the deliveredResult.error guard, the relevantHeldRows domainsMatch post-filter, the per-recipient merge Map, and the perRecipientMap.has(input.recipient) reporter-fallback all unchanged — the Map already keyed on row.to, so no merge-logic change was needed for multi-recipient correctness.
  • Updated the inline comments above the fan-out Promise.all and above the per-recipient merge block to document that the query is now tenant-wide, scoped only by sender+subject+date-window, and that the Map naturally produces one entry per distinct recipient.
  • BlastRadiusInput was not touched — recipient remains required (T-17-01) and is still used to label the reporter in the merge.

Task 2 — Update tests for the broadened fan-out (lib/services/mimecast-blast-radius.test.ts, commit 534eda3)

  • Updated the "calls getHeldMessages with the SAME start/end window..." test: getHeldMessages assertion changed from { recipient, start, end } to an exact { start, end } object (no recipient key); added a new assertion that the searchDeliveredMessages call argument does not have a to property.
  • Added a new test, "returns every distinct recipient from a multi-recipient delivered result (true blast radius)": mocks searchDeliveredMessages with three delivered rows sharing the same sender/subject but three distinct to addresses (reporter, coworker-a, coworker-b), and asserts delivered === 3, matched === 3, and all three recipients appear in perRecipient with status 'delivered'.
  • All other existing tests (unavailable, cache hit, injected tenant client, Bug 1 defense-in-depth, unrelated-sender held filter, same-domain held override) left unchanged and still pass.

Verification

  • npx vitest run lib/services/mimecast-blast-radius.test.ts — 13/13 tests passed.
  • npx tsc --noEmit --pretty — clean, no errors anywhere in the repo.
  • grep -n "to: input.recipient\|recipient: input.recipient" lib/services/mimecast-blast-radius.ts — no matches (both scoping params fully removed from the API calls).

Deviations from plan

None. Both tasks executed exactly as planned.

Environment note (execution anomaly, not a code deviation)

This quick task's executor session was dispatched expecting an isolated git worktree (/opt/stacks/pulse/.claude/worktrees/agent-a136e97a6eadf5305), matching the standard worktree_branch_check protocol. During setup it was discovered that no such worktree actually existed on disk or in git's internal worktree registry (git worktree list) — the executor was, in practice, operating directly against the main checkout at /opt/stacks/pulse on master. The coordinator confirmed this was the intended non-worktree-isolation fallback path for this quick task (equivalent to workflow.use_worktrees=false) and explicitly approved committing directly to master, consistent with the plain sequential-commit pattern already used for quick task 260721-fy8 immediately prior in this same repo. No work was lost: the one git reset --hard run during verification was a no-op (master was already at the expected pre-dispatch-plan commit f50b8a3a, confirmed via git reflog), and the working tree was clean throughout. Both task commits (58202e0, 534eda3) landed directly on master as a result.

Self-Check

  • FOUND: lib/services/mimecast-blast-radius.ts (modified, commit 58202e0)
  • FOUND: lib/services/mimecast-blast-radius.test.ts (modified, commit 534eda3)
  • FOUND commit 58202e0 in git log
  • FOUND commit 534eda3 in git log

Self-Check: PASSED