Skip to content

fix(hive): mail to an archived agent is filed, and its sender is told nobody is there - #512

Open
gpechieu wants to merge 2 commits into
chaitanyagiri:mainfrom
gpechieu:fix/archived-recipient-notice
Open

gpechieu wants to merge 2 commits into
chaitanyagiri:mainfrom
gpechieu:fix/archived-recipient-notice

Conversation

@gpechieu

@gpechieu gpechieu commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

What & why

An archived agent (its terminal is gone) keeps its inbox, so a message to it lands there, is logged as delivered, and stays unread. Filing it is right — a worker re-hired under the same id reads it on its first turn (#472 settles a released worker's inbox only up to its done signal) — but the sender learned nothing: god kept mailing dead agents for hours (seen live 2026-08-16), and a request to a worker nobody re-hired was simply lost.

Now a direct message to an archived recipient is still filed (and logged archived-recipient), and when it expects an answer (request / query / propose) and the sender is a live agent, the sender gets an immediate inform from system, threaded on the original (in_reply_to, conversation, hops + 1, requires_reply: false so it can never ping-pong): [no one is there to answer — "<id>" is archived] <subject>, with what to do about it (route to a live agent or hire one). Inform-only mail is filed quietly; broadcasts already skip archived agents; god (the bounce target) is never treated as archived.

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Docs
  • Build / CI

Evidence

Before

before

On main the new test is red: the request is filed and reads as delivered, and the sender's inbox stays empty.

After

after

Same test with the fix: filed verbatim, the sender holds the notice, the ledger has the archived-recipient entry and the message log still reports the delivery that happened.

How I tested it

  • OS: macOS 15 (Darwin 25.6), Node 22, branch cut from main @ 417d8de
  • Steps:
    • node --test test/hive-archived-recipient.test.cjs → 3 of 4 fail on main (src stashed), 4/4 pass with the fix.
    • npm run typecheck clean; npm run test:focused 838/838.
    • The four cases: request → filed + notice (act, from system, in_reply_to, requires_reply false, subject prefix, body) + log + delivered list; query/propose notify while inform/done are filed quietly; a live non-god sender is notified and a sender off the roster (system) is not; an unarchived agent gets ordinary mail again.

Credit (optional)

Discord:

X:

Checklist

  • Before and after evidence is attached above, under both headings.
  • npm run typecheck passes.
  • npm run test:focused passes.
  • npm run build succeeds.
  • This PR is one change. Unrelated fixes belong in their own PR.
  • I read the diff myself before opening this, and there is no debug output, commented-out code, or unrelated formatting churn in it.
  • Any new UI derives from DESIGN.md / tokens.ts — no ad-hoc colors, spacing, or fonts. (no UI)
  • If I added art, it's my own or compatibly licensed, and listed in ATTRIBUTION.md. (no art)

🤖 Generated with Claude Code

… nobody is there

An archived agent (terminal gone) keeps its inbox, so a message to it lands
there, is logged as delivered, and stays unread. Filing it is right — a
worker re-hired under the same id reads it on its first turn, and a released
worker's inbox is settled only up to its done signal — but the sender learned
nothing: god kept mailing dead agents for hours (seen live 2026-08-16), and a
request to a worker nobody re-hired was simply lost.

routeMessage(): a direct message to an archived recipient is still delivered
(and logged `archived-recipient`). When it expects an answer (`requires_reply`:
request / query / propose) and the sender is a live registry agent, the sender
gets an immediate `inform` from `system`, threaded on the original
(in_reply_to, conversation, hops + 1, requires_reply false so it can never
ping-pong): "[no one is there to answer — "<id>" is archived] <subject>" with
what to do about it (route to a live agent or hire one). Inform-only mail is
filed quietly; broadcasts already skip archived agents; god (the bounce
target) is never treated as archived.

Test: request → filed verbatim + notice to the sender + log entry + message
log still reports the delivery; query/propose notify, inform/done do not; a
live non-god sender is notified, a sender off the roster ("system") is not;
an unarchived agent gets ordinary mail again.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
gpechieu added a commit to gpechieu/munder-difflin that referenced this pull request Sep 14, 2026
…esign, OpenWolf transient), PRs chaitanyagiri#512 aviso a remitente con destinatario archivado y chaitanyagiri#513 exit en dev, 6 fixes integrados (891/891), boot real 11:50 OK - Agente Claude-IMPLEMENTADOR - TESTED

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WmYD63qADnKFKjpU1Ar3TF
…routed, not dropped into an inbox

Self-review (CONTRIBUTING: run your agent over your PR). An archived agent on a hookless or proxy-tier engine hit the terminal-handoff branch first: nothing filed, no log, no notice. The archived branch now runs right after the assistant bounce, so with no terminal the inbox is where the mail goes whatever the engine. The notice goes through routeMessage, so a sender on such an engine receives it the way it receives any mail (terminal handoff, or the god bounce when no renderer is there); requires_reply false and the live-sender guard keep it from re-entering. Dropped the redundant sender-is-target guard. Test: an archived custom-engine agent is filed and its sender told; a custom-engine sender is told through routing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@gpechieu

Copy link
Copy Markdown
Contributor Author

Agent review of this PR (CONTRIBUTING: "run your coding agent over your own PR, and paste what it found"). Claude Code went over 417d8dec..ce221cea for cross-platform behaviour, paths with spaces, provider neutrality, hot paths and security, then hygiene.

  • Cross-platform / paths with spaces: clean — only join() / existsSync / atomicWriteJson; filenames are harness ids; no shell.
  • Provider neutrality — two things it flagged, both fixed in be60a47:
    • The archived branch sat after the hookless and proxy-tier branches, so an archived target on those engines never reached it: the mail went to the terminal handoff (there is no terminal), nothing was filed, no log, no notice. The archived check now runs right after the assistant bounce — with no terminal the inbox is where the mail goes, whatever the engine.
    • The notice was deliver()ed straight into the sender's inbox, which a hookless / proxy-tier sender never drains. It now goes through routeMessage, so such a sender receives it the way it receives any mail (terminal handoff, or the god bounce when no renderer is there). requires_reply:false and the live-sender guard keep it from re-entering; hops are +1.
  • Hot paths: clean — reuses reg, one O(1) lookup, extra I/O only on the archived path.
  • Security / loop risk: clean — the notice cannot ping-pong (requires_reply:false, archived senders are never notified, a reply to system hits the existing no-inbox drop + bounce once); the subject echoes the sender's own text; the target id is a registry key.
  • Hygiene — fixed: the redundant msg.from !== t guard (targets already exclude the sender).
  • Flagged and deliberately not changed: if deliver() fails for an archived id the continue skips the base no-inbox bounce — theoretical, no flow deletes an agent dir while keeping its registry entry; harness senders that are not registry agents (scheduler, breaker, the literal 'god' used by the worker dispatch) get no notice — they cannot be mailing an archived agent in practice (the dispatch targets a worker that was just spawned).

Verified after the fix: typecheck clean, the test file 5/5 (new case: an archived custom-engine agent is filed and its sender told; a custom-engine sender is told through routing), local suite 839/839.

@gpechieu

Copy link
Copy Markdown
Contributor Author

Housekeeping, no code change: I force-pushed this branch to reword the commit messages (an internal session trailer was dropped; Co-Authored-By stays) and replaced the evidence images with plain test-runner output, since the previous captures included local session data that should not have been published. The diff is byte-identical to what was reviewed (git diff between the old and new heads over src/test is empty); the review comments above cite the previous hashes. Sorry for the noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant