Skip to content

Mailbox reason and dismissal cannot express a thread-backed refusal, so the CLI promises a retry that never comes #226

Description

@pseudoseed

Two findings from #221's review that belong with #223's migration, not before it. Both are about
the same thing: the mailbox row's vocabulary cannot express what actually happened, so the route
picks the nearest word and the CLI repeats it as if it were checked.

1. Every non-delivered status is reported as held / no-live-pty

tower-routes.ts:2229 is const reason: MailboxReason = stored?.reason ?? 'busy', and the
delivery path holds nearly everything as no-live-pty. So afx send tells a user their message
is queued and will arrive when the recipient's session frees up — for a thread-backed row whose
backend is not initialised in Tower's process, where no session will ever free up because there is
no session.

The CLI promises a retry that will never come. That is worse than an error, because the user
stops looking.

2. dismiss() is documented as operator-initiated and now carries system refusals

mailbox.ts:413-418: "Transition a held row to dismissed (operator-cleared via afx inbox dismiss)". #221 made the delivery path call it for a --no-enter message to a thread-backed
agent, which is correct behaviour — the row can never be delivered and holding it raises a
starvation notice with no remedy — but it makes the docblock false, and a dismissed row now
means either "a human cleared this" or "the system refused it", with nothing distinguishing them.

That is the same defect class as everything else in that PR: one word for two facts.

The right shape, and why it is one change

Move the refusal to the SEND path. afx send --no-enter to a thread-backed agent should fail
at the CLI, where a human is watching and can act, rather than being accepted, queued, and quietly
terminated at drain time. The drain-time refusal then becomes an honest backstop for rows enqueued
before the recipient became thread-backed, rather than the primary mechanism.

That wants the same migration #223 wants: the reason vocabulary has to grow before either of these
can be reported truthfully, and dismissed needs a companion (or a discriminator) for
system-refused. One migration on the user-global global.db, not two.

Filed from #221's round-4 review; the architect's ruling was to keep #221 to proving #179 items 3
and 4 and the instrument bugs that made them unrunnable.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/towerTower, afx, terminals, messaging

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions