Label Alfred's own outbound mail instead of dropping it silently (#285)#392
Merged
Conversation
Alfred's briefing + HIL-approval mail ships through Resend and re-enters the connected Gmail as inbound mail. Since #211/#266 it is dropped at ingest (never a document, never triaged, never a sender prior) to break the self-amplification loop — but that left it unorganised and invisible. Apply a dedicated `Alfred` Gmail label on the same drop path so the user can find that stream, without reopening the loop: the message is still dropped from `documents`/triage/briefing input; only a label is added. - labels.ts: `ensureAlfredSelfLabel` (cached on `metadata.alfredSelfLabel`, race-safe create, force-rebuild) + `labelSelfAuthoredMail` (idempotent skip when already labelled, self-healing force-retry on a stale-label 404, injectable deps for tests). Deliberately kept out of `AlfredLabelMap.allIds` — self-mail is never triaged, so it must not intersect the relabel/strip set. - ingestor.ts: `persistMessage` tags the message in the `isSelfAuthored` branch before returning `ignored`. Best-effort — a label failure never blocks the drop. - backfill-label-self-mail-committed.ts: one-off catch-up over existing self-mail (dropped from the DB, so it reads Gmail directly), matching the current send address ∪ historical aliases; dry by default. Bundled as a tsdown entry. - Tests: 5 cases over the DI seam (apply / skip / retry / bubble). Prod dry-run: 159 unlabelled self-mail across 2 accounts (58 from the historical alias, which a current-address-only match would miss). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #285.
Problem
Alfred's own outbound — the daily briefing and HIL-approval requests — ships through Resend and re-enters the connected Gmail as ordinary inbound mail. Since #211/#266 it's dropped at ingest (
isSelfAuthored→outcome: "ignored") so it never becomes a document, never gets triaged into the demanding lanes, and never seeds a sender prior — that closed the self-amplification loop. But it also left this mail unorganised and invisible: it just vanishes.Fix
Apply a dedicated
AlfredGmail label on the same drop path, so the user gets a coherent, findable stream — without reopening the loop. The message is still dropped fromdocuments/ triage / briefing input; the only new effect is a label.Changes
labels.tsensureAlfredSelfLabel— ensures theAlfredlabel exists, cached onintegrationCredentials.metadata.alfredSelfLabel(jsonb_set so it never clobbersalfredLabels/watch state), race-safe create (409 → re-list), force-rebuild for a deleted-out-of-band label. MirrorsensureAlfredLabels.labelSelfAuthoredMail— idempotent (skips the modify round-trip when the label is already on the message, which matters because the 5-min realtime poll re-lists self-mail every window — it never becomes adocumentsrow so the known-id pre-filter can't drop it), self-healing (a stale-label 404 triggers a force-rebuild + one retry), and takes injectable deps so the skip/retry logic is unit-tested without a live mailbox.AlfredLabelMap.allIds— that set is the triage category labels the relabel path strips/swaps between, and self-mail is never triaged, so the two must not intersect.ingestor.ts—persistMessagetags the message in theisSelfAuthoredbranch before returningignored. Best-effort: a labelling failure is logged and never blocks the drop (the drop is the real guardrail). ThreadscredentialId+accessTokenthrough (all three ingest paths already have them).backfill-label-self-mail-committed.ts— one-off catch-up for self-mail that landed before this shipped. Those messages were dropped from the DB (Briefing: Alfred re-ingests & re-triages its own briefing emails (self-feedback loop) #211/Residual self-ingestion: Alfred's own briefing + HIL-approval mail tagged urgent on personal account (#211 follow-up) #266), so it reads Gmail directly:from:(<self addrs>) -label:"Alfred", thenbatchModifyin ≤1000-id chunks. Matches the current send address ∪ historical aliases (--aliases, defaultyash@croisillies.xyz) — the retire-backfill precedent. Dry by default;--commitwrites. Bundled as a tsdown entry.Acceptance criteria
RESEND_FROM_EMAIL), soisSelfAuthoredcovers both.Verification
pnpm check-types✅,pnpm lint✅ (2 pre-existing unrelated web warnings), server bundle builds with the new entry ✅5 new tests + existing
self-authored-drop+reconcile-thread-labelregression suites — 47 passProd DRY-RUN (read-only, via a self-contained
railway sshcount): 159 unlabelled self-mail across 2 accountshey@alfred.beautyyash@croisillies.xyz(alias)58 of the 159 come from the historical alias — a current-address-only match would miss them, confirming the alias handling.
Rollout (post-merge)
Deploy, then run the backfill against prod:
node dist/scripts/backfill-label-self-mail-committed.js --emails=yashgouravkar@gmail.com,yash.k@oliv.ai --commit🤖 Generated with Claude Code