Skip to main content

Email-Reactor fail-closed fix — classifier failure / partner mail no longer auto-archived (MC #103815)

Incident / Root Cause

~/system/daemons/email-agent.js was FAIL-OPEN. When Ollama classification failed (request timeout, JSON parse error, or no-JSON-match), ollamaClassify resolved to {category:'INFO', priority:'low'}. The auto-archive block then archived any info/spam/own row. The strategic-partner elevation block only ran when dbCategory === 'ACTION', so a misclassified partner email was never elevated.

Net effect: A revenue email from strategic partner Asmir Merdžanović ("QODY" project, email #9661, 2026-06-13) was silently auto-archived and never answered until he re-sent it 2026-06-17.

Fix (FAIL-CLOSED) — 3 Changes

  1. All three ollamaClassify failure branches now resolve {category:'ACTION', priority:'medium', _classifyFailed:true} with distinct reason (timeout/parse_error/no_json) — an unclassifiable email defaults to actionable, never FYI/archive.
  2. matchStrategicPartner() now runs independent of category (guard if (!ARGS.dryRun)); on a partner match it elevates to ACTION via emailInbox.updateClassification(...,'ACTION','high'), sets partner_tier, fires CEO push.
  3. Auto-archive is guarded by _skipArchiveDueToClassifyFail and partner-elevated rows (cat patched to 'action') never reach the archive branch.

New helper: updateClassification(id, classification, priority) added + exported in ~/system/tools/email-inbox.js.

Verification

  • node --check clean on both files
  • Simulation harness /tmp/evidence-103815/sim.test.js = 39 PASS / 0 FAIL incl. the exact Asmir/QODY regression
  • Independent verification: native verifier (7/7 atomic claims) + Proveo P2P PASS (mesh-thr-95c7fb0b / mesh-msg-008f947c)

Deployment

Daemon com.john.email-agent is StartInterval (spawns fresh node each cycle) → fix is live on the next cycle, no restart needed.

Residual Known Gap (Follow-on MC #103819)

Two heuristic INFO fallbacks OUTSIDE ollamaClassify (circuit-breaker path ~L2161 and promise-rejection catch ~L2177) do not yet carry _classifyFailed; narrow exposure (non-partner email during Ollama TCP error / breaker-open with no heuristic keyword match).

Lesson

Email triage must FAIL-CLOSED — an email the classifier could not process must never be silently archived; strategic-partner safety net must be category-independent.


Evidence bundle: /tmp/evidence-103815/
MC task: #103815
Date: 2026-06-17