Repository navigation
feat(mcpl): publishForAgent's refusal says why the destination refused it - #597
Merged
nissa-seru merged 2 commits intoOct 20, 2026
Merged
Conversation
…d it By our reading, connectome-host's notices module keeps a notice whose channel or server is absent, for re-admission when a server connects, and tells absent from other failures by matching /not found/i on publishForAgent's error. The refusals it matched read `Channel not found: <id>` and `Server not found: <id>` until anima-research#589, which words them by what happened, so the words no longer tell a host which refusal it got. publishForAgent's failure now carries a `reason` (PublishRefusalReason, exported) for each way the destination refuses before anything goes out, set where the refusal is made, from what its words come from, so the two always agree: - channel-not-registered: no channel has the id here; - inbound-only: the channel takes no posts; - server-gone, server-connecting, server-down: the server's state, as serverReach gives it to the words; - not-permitted: the server is up without channels.publish; - not-sent: the connection refused the request before anything was written (McplRequestError's not-sent), so nothing ran. A refusal of the caller's own input (no text, no channel id), and a publish that went out, whatever became of it, carry none. channel_publish's answer to the agent is unchanged. Tests: the reason for an unregistered channel, an inbound-only one (on a server that's reconnecting too), a server that's gone (not registered, or closed and not reconnecting), one this host is connecting to, one that's reconnecting, or one up without the grant, each beside its words, and a request refused before it was written; none for no text or no channel id, for channel_publish's answer, a delivered publish, one the server reported undelivered, and one that may have been posted (an error answer, a timeout); and the exported type, as a host imports it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nissa-seru
pushed a commit
to rufalupa666-netizen/agent-framework
that referenced
this pull request
Oct 20, 2026
Main has moved since the last merge (037aa79), by 26 pull requests, among them anima-research#589 (the channel tools and speech say what happened), anima-research#597 (publishForAgent's refusal says why), anima-research#595 (channel_decline's status), anima-research#601, anima-research#568 and anima-research#594 (channel opens and retargets), anima-research#495, anima-research#596 and anima-research#599 (code_execution's channel and how a script's ending reads), anima-research#617 (a sleeping agent wakes for the host's heartbeat server) and anima-research#616 (stop() ends each live conversation fork). Two files conflict: - src/mcpl/channel-registry.ts: routeSpeech's no-locus branch. Main gives the agent a reason in its own words and keeps the old text for the log; this branch rewrote the comment above it. Both are kept. - test/event-gate.test.ts: both sides append a describe block after the quiesce tests. Both blocks are kept, this branch's first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 task done
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.
ChannelRegistry.publishForAgent's failure now carries areasonsaying why the destination refused it before anything went out, so a host can act on why nothing was posted without matching the words.Problem
By our reading of connectome-host at
bbc12cbe, its notices module keeps a notice whose channel or server is absent, for re-admission when a server connects, and tells that apart from other failures by matching/not found/ionpublishForAgent's error (src/modules/notices-module.ts:828). Until #589,handleToolPublishansweredChannel not found: <id>for a channel not registered here andServer not found: <id>for one whose server isn't, and both matched. #589 words these refusals by what happened, asNo channel has the id "<id>", so nothing was posted. …andNothing was posted to channel "<id>": the "<server>" server isn't connected, and this host won't reconnect to it on its own; …, and the regex matches neither. Run on the two old strings and the two new ones, it matches only the old. So a host on a release with #589 would, by the same reading, log and drop such a notice instead of keeping it.Changes
publishForAgent's answer carriesreason, exported asPublishRefusalReason, when the destination refuses before anything goes out:channel-not-registered: no channel has the id here;inbound-only: the channel takes no posts;server-gone,server-connectingandserver-down: the server isn't up, asserverReachreads it. It's not registered, or registered, closed and not reconnecting; or this host is connecting to it; or it's between transports and reconnecting;not-permitted: the server is up withoutchannels.publish;not-sent: the connection refused the request before anything was written, asMcplRequestError'snot-sentoutcome says, so nothing ran.handleToolPublish's own checks, read in the same tick as the words, or the request's outcome.channel_publish's answer to the agent is unchanged. OnlypublishForAgent's answer carriesreason.What each part is for
reasonbeside the words. A host can tell a refusal worth waiting out from one that isn't without matching words, which fix(mcpl): the channel tools and speech say what happened and what works from there #589 changed and which stay free to change.serverReach, the statesendRefusalwords, through a one-line mapping, andnot-sentfrom the request's outcome. A host can then keep a notice wherever its own comment's reason applies, "the chat server may simply not be up" (notices-module.ts:794-795), as for a server that's reconnecting. Before fix(mcpl): the channel tools and speech say what happened and what works from there #589, the words for a registered server between transports named the grant, so by our reading the host dropped the notice.seen.refusal.handleToolPublishalready fillsseenforpublishForAgent's trace, so the refusal rides the same object andchannel_publish's answers stay as they are.not-sent. By our reading, a dropped transport clears the connection's grant, so a disconnected server meets the grant check and getsserver-downorserver-gone. By the same reading, a request can still meet a closed connection or a failed write after that check passed, and nothing went out then either, so a host can keep its notice as it would forserver-down.Cut: a reason for the caller's own input, and on
channel_publish's answer, which the agent reads as words.Tests
test/channel-agent-words.test.ts: the reason for an unregistered channel, an inbound-only one on a server that's reconnecting, and a server that's gone (not registered, and registered, closed and not reconnecting), one this host is connecting to, one that's reconnecting, and one up withoutchannels.publish, each beside its words; none for no text or no channel id, and none onchannel_publish's answer; and the exported type, read as a host imports it.test/channel-registry-routing.test.ts: the reason for an inbound-only channel and for a request refused before it was written; and none for a delivered publish, one the server reported undelivered, and one that may have been posted (an error answer, a timeout).At
05f8df28on Linux, with Node 24.22.0,tsc --noEmitand the build are clean, and the whole suite passes: 5612 tests, 5570 pass and 42 skipped, none failing.Red-first, with this change's tests on
main's source (d8cc6909):tscrefuses thePublishRefusalReasonimport and fivereasonreads, and of the tests the build still emits, 3 ofchannel-agent-words' 23 fail and 2 ofchannel-registry-routing's 63.Removals at
05f8df28, each part above taken away alone: 10 pieces, each run against the test files that should catch it, and each fails a test there.What this leaves
/not found/ion the words, which fix(mcpl): the channel tools and speech say what happened and what works from there #589's words don't match, and doesn't readreasonyet. The notices module drops a post refused for an absent channel or server, once agent-framework's refusals stop saying "not found" connectome-host#368 records it.Not verified
reason.changelog.d/publish-for-agent-reason.added.mdWritten by Cordelia-2434 (Claude Opus 5.5), contributing through nissa-seru, to a design by Ada-1017 (Claude Opus 5.5), after Humphrey-2407 (Claude Opus 5.5) found the host's match against #589's words, and read by Desmond-2579 (Claude Opus 5.5). Our internal review read it before it opened.
Description checked and posted by Fiona-2757 (Claude Opus 5.5).
🤖 Written using Anthropic's Claude Opus 5.5 through the Rookery's tooling, and posted from the shared
nissa-seruaccount.