# Phase 17: Mimecast Blast Radius Lookup - 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-15
**Phase:** 17-mimecast-blast-radius-lookup
**Areas discussed:** Query strategy, Clicked count, Persistence, Caching

---

## Query Strategy

| Option | Description | Selected |
|--------|-------------|----------|
| Try Message-ID first, then fan out | Call `getMessageInfo(messageId)` first for an exact match; if that misses, fan out to `searchDeliveredMessages` + `getHeldMessages` + `getThreatEvents` keyed on sender/subject/date-window and merge into one normalized count. | ✓ |
| Message-ID only, fail to unavailable | Only call `getMessageInfo` by Message-ID; return unavailable if no exact match. | |
| Always fan out (no Message-ID short-circuit) | Skip `getMessageInfo` entirely; always query the three fallback methods. | |

**User's choice:** Try Message-ID first, then fan out (recommended option).
**Notes:** None.

---

## Clicked Count

| Option | Description | Selected |
|--------|-------------|----------|
| Best-effort from threat events | Derive `clicked` from `getThreatEvents()` where Mimecast's TTP URL Protect logs a click as a threat-event subtype; 0 (not unavailable) if no match. | ✓ |
| Always 0 / not implemented | Hardcode `clicked: 0` with a comment noting future work. | |
| Add a new MimecastClient method for click logs | Research and add a dedicated `getUrlClickLogs()`-style method now. | |

**User's choice:** Best-effort from threat events (recommended option).
**Notes:** None.

---

## Persistence

| Option | Description | Selected |
|--------|-------------|----------|
| Ephemeral only | Pure function call, no new table/column; Phase 19's classifier decides whether to persist via `classifications.reasons`. | ✓ |
| Persist to a new column/table now | Add a migration now (e.g. `reports.blast_radius` JSONB or a dedicated table). | |

**User's choice:** Ephemeral only (recommended option).
**Notes:** None.

---

## Caching

| Option | Description | Selected |
|--------|-------------|----------|
| No caching in this phase | Keep Phase 17 scoped to the lookup abstraction; add caching later if needed. | |
| Redis-cache by message identity | Use `lib/services/redis-client.ts` to cache blast-radius results keyed on message identity, short TTL. | ✓ |

**User's choice:** Redis-cache by message identity.
**Notes:** Follow-up question asked for TTL specifics.

### Cache TTL (follow-up)

| Option | Description | Selected |
|--------|-------------|----------|
| 5 minutes | Matches the existing `integration-health.ts` cache pattern. | ✓ |
| 1 hour | Longer TTL, fewer API calls for legitimately-repeated lookups days later. | |
| No expiry — manual invalidation only | Cache indefinitely, needs explicit invalidation path. | |

**User's choice:** 5 minutes (recommended option).
**Notes:** None.

---

## Claude's Discretion

- `isMimecastConfigured()` helper location (in `mimecast-client.ts` vs. a new `mimecast-factory.ts`)
- New module name/location for the blast-radius abstraction itself
- Exact normalized output TypeScript shape (field names, per-recipient status enum values)
- Date-window sizing for the fan-out fallback query
- Redis cache key exact format

## Deferred Ideas

- Dedicated Mimecast click-log API method (`getUrlClickLogs()`-style) — deferred, future work if best-effort click derivation proves insufficient
- Persisting blast-radius results to a new table/column — deferred to Phase 19 or later if audit/idempotency needs surface
