Skip to content

AI intelligence (classify / extract / persist / isolation)

Duckbill™ turns mail into reviewable signals. Model output is advisory. It never sends, deletes, archives, or writes back to a mail provider.

Boundary

AI runs against MailMessage. MessageInstance context is optional and only stored when it materially affected the result. A second instance of the same message does not create a second classify inference when the input fingerprint matches.

UNPROCESSED is a valid classification. Sync upserts and CLASSIFY enqueue stay independent: AI enqueue or inference failure cannot block mail visibility.

Modules

ModuleResponsibility
ai-inference.tsVersioned DTO, JSON-schema validation, immutable insert, current pointer
classify.tsIntent / attention / priority with configured confidence bands and abstention
extract.tsAction items, deadlines, and entities with evidence + inference id
summarize.tsMessage and bounded thread summaries; original body stays authoritative
ai-isolation.tsTimeouts, prompt injection, enqueue isolation, no adapter writes

Persistence

Every model call used for a persisted decision becomes an AIInference row with provenance: task, model/provider, prompt/schema/taxonomy versions, input fingerprint, structured output, confidence, validation status, and error/abstention reason.

Reprocessing inserts a new row. current_ai_inferences is the current pointer. Inference rows are insert-only; the database rejects UPDATE and DELETE.

Invalid JSON or enum values are retried, then recorded as validation_status = error. They are never written as business Classification values.

Policy port

Stream B calls Stream A's evaluatePolicy (actor: AI) before any side effect. If the gateway is missing, this layer denies send, delete, archive, write-back, contact merge, and provider mutation locally. Even a permissive gateway cannot authorize those actions from inference. Deterministic skip_ai matches from MAIL-86 may skip the model.

ENABLE_SEND stays off. Recommended actions in model output are display-only.

Isolation

Golden-set evaluation (MAIL-36 / MAIL-57) and draft generation (MAIL-170 / MAIL-173) are separate streams. Human overrides (MAIL-54) designate current_classifications without rewriting inference history. See human corrections and ADR 0024.