Repository navigation
Harden AgentMail CLI security, delivery recovery, and durable ingress - #10
Merged
Merged
Conversation
# Conflicts: # README.md # src/channel/src/catch-up.test.ts # src/channel/src/catch-up.ts # src/channel/src/durable-receive.ts
Combines PR #8 (durable ingress edge cases) into PR #10 so both land as a single change. Conflict in src/channel/src/ingress.ts resolved toward this branch's transitionFailedAgentMailIngress helper, which already consolidates the poison-message failure transition that origin/luanda still open-coded at both call sites. The helper's callers supply the distinct terminal log text and lastError, so the "abandoned deferred turns" and "failed dispatch attempts" paths keep their separate messages. The helper omitted the failedAt stamp that the open-coded blocks passed to journal.fail, which durable-receive.ts maps to completedAt for failed rows. Added it back so the consolidated path matches the two direct journal.fail call sites in this file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Addresses consolidated review feedback across three rounds. outbound-route: the "unrelated active session" decline now only fires when more than one account is configured. With a single account the inference cannot pick a wrong inbox, and declining dropped routing back to core's `dmScope ?? "main"`, collapsing every thread into one session. Account inference is also validated against the configured account list, so a stale session key for a removed account can no longer skip the multi-account decline and resolve a synthesized account with an empty inboxId and no apiKey. catch-up: retention is filtered on the same effective provider time the row is admitted with, so a malformed sender date cannot fall through to the createdAt fallback unfiltered and re-admit mail whose tombstone has expired. Rows admitted ahead of the sweep clock are remembered by id in the cursor, so a future-dated row no longer re-enters the admission chain (and inflates the admitted count) once a minute for up to the full 24h skew horizon. The memo is measured against the run clock rather than a resumed continuation's rewound bound, and bounded by serialized bytes as well as entry count so long provider ids cannot push the cursor past the keyed store's 64KB limit and strand catch-up in its retry loop. inbound: the abort-path media cleanup is registered with the account reclaimer before it starts, so shutdown awaits the unlink instead of exiting with it in flight. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sidharth0612
approved these changes
Aug 23, 2026
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.
Consolidates #8 into this PR so the AgentMail CLI/identity work and the durable ingress hardening land as one change. #8 is closed in favour of this branch; its six commits are merged here unchanged.
CLI security and delivery recovery (originally this PR)
Closes the AgentMail identity boundary by resolving CLI credentials from plugin/secret configuration, stripping inherited credential/header/endpoint state, validating restricted options independently of CLI grammar, and aligning the shipped skill and SecretRef documentation with that model. Keeps healthy quiet WebSocket connections alive while preserving stability-gated reconnect backoff, and hardens REST recovery with malformed-page handling, independent normal/deep continuations, retention-safe resume, and monotonic high-water commits. Also fixes canonical multi-account session routing, adds preparation-lock leases and complete cross-platform package validation, normalizes mailbox/media inputs, removes duplicate CLI metadata, and consolidates ingress failure transitions.
Durable ingress edge cases (merged from #8)
Hardens durable AgentMail ingress across deferred media ownership, capacity coordination, tombstone retention, catch-up recovery, reply reconciliation, and reconnect behavior. Admits sender-clock-skewed mail while bounding retention at the shared durable boundary; self-heals cursor baselines without regressing their high-water marks and prevents malformed timestamps from being re-listed forever. Preserves core empty-payload suppression, bases unknown-send 404 recovery on the outbound attempt, and reclaims deferred media after account shutdown settles.
Merge resolution
The two branches conflicted only in
src/channel/src/ingress.ts(2 hunks); every other shared file auto-merged. Resolved toward this branch'stransitionFailedAgentMailIngresshelper, which already consolidates the poison-message failure transition that #8 still open-coded at both call sites. The helper's callers supply the distinct terminal log text andlastError, so the "abandoned deferred turns" and "failed dispatch attempts" paths keep their separate messages.One fix was needed on top of the mechanical resolution: the helper omitted the
failedAtstamp that the open-coded blocks passed tojournal.fail, whichdurable-receive.tsmaps tocompletedAtfor failed rows. Restoring it keeps the consolidated path consistent with the two directjournal.failcall sites in the same file, and is covered by thefails repeatedly abandoned deferred turns at the dispatch ceilingtest from #8 (which fails without it).Validation
31 files changed, +1963 −488.
npm test215 passed (14 files),npm run build, andnpm run plugin:validate— manifest check plus host load of the AgentMail channel with AgentMail CLI 0.7.14 across all 8 bundled targets — all pass on the merge commit.