Jev email triage · reliability upgrade

Progress survives. Inputs stay untouched. Time becomes explicit.

The triage now guarantees a distinct output path, checkpoints every completed email, resumes interrupted work, supplies calendar age to Jev, and validates each structured answer before saving it.

Merged to main · 19 September 2026
12/12live held-out cases passed
0live evaluation errors
1.60 smedian live Jev latency
$0.000357total live evaluation cost

What changed

The upgrade concentrates on data safety, interrupted-run recovery, time-aware decisions, and repeatable measurement.

Data safety

Input and output cannot collide

outputPath() handles .json case-insensitively, appends a suffix when no extension exists, resolves both paths, and asserts that they differ.

Recovery

Atomic progress checkpoints

Full runs write a separate .partial file after every email. --resume skips completed IDs and continues the interrupted run.

Finalization

Replace output only when complete

Each checkpoint uses a temporary file and rename. The final output is promoted only after all selected emails succeed, then the partial file is removed.

Clock

Jev receives age, not a bare date

The state includes today and computed age_days. The importance rubric explicitly says an expired deadline is not urgent.

Validation

Malformed records fail clearly

Every input field must be a string. Category and importance must be valid, and both boolean probabilities must be finite values from zero through one.

Evaluation

Twelve public synthetic cases

Security, receipts, service notices, newsletters, reminders, business inquiries, sponsorship, phishing, and an expired deadline share one JSONL result contract.

Why these changes were needed

BeforeFailure modeNow
Only lowercase .json was replaced in the filename.An uppercase extension or extensionless input could become its own output and be overwritten.Output naming is case-insensitive, suffix-safe, resolved, and asserted distinct.
Results were written after the last email.A late failure discarded every earlier paid decision.Each successful row is atomically checkpointed and resumable.
Jev received the email date without the current date.It could treat a months-old phrase such as “due tomorrow” as urgent today.The model receives today and age_days; the old-deadline test scored 0.19 importance.
Answer fields were read directly.A missing or malformed probability could silently become an unusable result.Invalid structured responses stop before persistence.

How a full run works

Read

Parse and validate the JSON array and command-line options.

Resume

Load the partial file and build a set of completed message IDs.

Enrich

Compute today and age_days before calling Jev.

Checkpoint

Validate the answer and atomically save accumulated rows.

Promote

Write the complete final output, then remove the partial checkpoint.

npm test
npm run eval:live
node --env-file=.env triage.mjs emails.json
node --env-file=.env triage.mjs emails.json --resume
node --env-file=.env triage.mjs emails.json --limit 5 --raw

What the evidence says

SignalMeasured resultInterpretation
Offline checks12/12 plus focused path and age assertionsThe runner, safety checks, evaluation contract, and age calculation are deterministic.
Live Jev evaluation12/12, 0 errorsAll reviewed categories, score ranges, and boolean decisions passed.
Expired deadlineImportance 0.19; confidence 0.87The new clock context corrected the known stale-urgency failure mode.
PhishingScam 0.98; importance confidence 0.00The scam decision was strong, while the importance score remained intrinsically uncertain.
SponsorshipBrand deal 0.98; scam 0.49The case passed, but the scam value sits one point below the operational threshold and deserves monitoring.