Skip to content

afx send: builder message routed to the wrong architect in a multi-architect workspace #47

Description

@pseudoseed

What happened

builder-experiment-39 sent a status message intended for its architect. It was delivered to the architect named main, not to its spawning architect uiv2. main had to forward it manually, noting it had landed in the wrong inbox.

Why this is a defect either way

The attribution in global.db is correct:

sqlite3 -readonly ~/.agent-farm/global.db \
  "select id, spawned_by_architect from builders where id='builder-experiment-39';"
builder-experiment-39|uiv2

So there are only two possibilities, and both are bugs:

  1. The builder used the bare afx send architect form. Documented behaviour is "From a builder: its spawning architect." spawned_by_architect is uiv2 and it resolved to main anyway, so the resolver is ignoring the column and falling back to the main-else-first-registered rule that is meant to apply only to non-builder senders.
  2. The builder used afx send architect:main explicitly. That is supposed to be refused. Per CLAUDE.md: "a builder may only use this for its own spawning architect — mismatches are rejected as spoofing." A builder reaching an architect that did not spawn it means the anti-spoofing check did not fire.

I cannot tell which from the outside, since the sent form is not recorded. That is arguably a third small gap.

Why it matters beyond one stray message

This is the multi-architect case the workspace explicitly supports (cluesmith#755, cluesmith#761, cluesmith#786, cluesmith#823). With two architects in one workspace, a builder's messages reaching the wrong one is not cosmetic:

  • The wrong architect receives blockers it has no context for and no authority over.
  • In this instance the misrouted message carried stale infrastructure state (it claimed a Cloudflare tunnel was live that had already been deleted). The architect that could have corrected it immediately never saw it, and the one that did see it correctly declined to act on another architect's builder. The correction took a manual relay.
  • It undermines the ownership boundary between architects, which is the entire point of named architects.

Reproduction sketch

  1. afx workspace add-architect --name other in a workspace that already has main.
  2. Spawn a builder from other.
  3. From the builder, afx send architect "test".
  4. Observe which architect receives it. Expected other; observed main in this case.

Suggested fix

  • Bare architect from a sender that is a builder must resolve through spawned_by_architect and must never fall back to the main-else-first rule. If the column is null, fail loudly rather than guessing — a message delivered to the wrong architect is worse than one that errors.
  • architect:<name> from a builder must be rejected unless <name> equals spawned_by_architect, which is the documented behaviour.
  • Record the address form used on the mailbox row, so misroutes are diagnosable after the fact.

Found while running two architects (main, uiv2) against separate builders in codev-1455.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/towerTower, afx, terminals, messagingbugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions