Repository navigation
fix(mcpl): a redaction that can't read its config withholds the text - #542
Merged
nissa-seru merged 1 commit intoOct 19, 2026
Merged
nissa-seru merged 1 commit into
nissa-seru merged 1 commit into
Conversation
A record of a server's text is redacted with the strings its configuration knows to be credentials. Reading them can throw: a legacy stdio MCPL server's env is a getter that derives the child's reaction baseline, and it throws while the Discord awareness ledger can't be read. The redaction then threw too, from four of the legacy connection's records: - reconnectOnce's catch records the failed attempt with the same configuration whose read just failed it. The attempt rejected with nothing to catch it, which by Node's default ends the process. The connection made no further attempt, and its close() rejected with the ledger's error. - The 'error' listener a handshake leaves once it has settled, and the one on a transport closed before it served, threw inside an I/O callback. - connectWithReconnect's catch rejected the connect instead of returning the stub that retries. serverTextRedactor, which redactServerText uses, now builds its patterns inside a try. When the configuration can't be read, that call returns WITHHELD_TEXT in place of the text, and the next call builds again. serverCredentialPatterns reads the url before the try that parses it, so an unreadable url is withheld too rather than taken for none. The framework's every-server redactor withholds the same way. So a redaction doesn't throw on a configuration it can't read, and a reconnect made while the ledger can't be read fails as a reconnect and is retried. The failure's cause still reaches the framework's trace through the reconnect-failed event. The framework reads the ledger before a legacy connect, which still ends startup on a ledger it can't read. A ledger that breaks after that read now leaves a reconnecting stub retrying until it reads again, as a reconnect does, and the comment beside the read says so. Under a configuration a host passes whose own getter throws, a failed tool call now answers with WITHHELD_TEXT, where a call the model or a script made got no result and an in-process call rejected, and startup's catch for a failed connect logs and goes on, where it ended startup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Required label not found on this PR. |
nissa-seru
pushed a commit
to nissa-seru/agent-framework
that referenced
this pull request
Oct 19, 2026
main now carries anima-research#542, whose redactions withhold the text, rather than throw, when the configuration they redact with can't be read. anima-research#542 lands ahead of this pull request, which takes its text where the two meet: - protocol-family.ts merges without conflict: anima-research#542's withheld text and its read of the url sit beside this pull request's JSON forms and its escape boundary. - The legacy error answer's log line redacts with the connection's configuration, so with anima-research#542 it withholds the message, where it threw, while a stdio server's reaction-baseline ledger can't be read. The call is still settled before the line is written. - mcpl-agent-words' test of an unreadable configuration now asserts the withheld line beside the call settled with the server's words. A new test has the logger throw on that line, which leaves the call settled only because it was settled first, so that order still has a test that fails without it. Receipts, on Linux. With this merge's src and tests, on Node 24.22.0: the sixteen changed or most affected test files, anima-research#542's three among them, pass, 400 tests. With src and changelog.d taken from main fe82187 and these tests, mcp-protocol-family can't load, since it imports logValueRedacted, which main lacks, and 26 tests fail across six other files. Each of 45 pieces, removed on its own at this merge, fails at least one test. The whole suite at this merge, each test file in a process of its own: the typecheck and the build are clean, and 240 files and 4,640 tests (4,623 passing, 17 skipped, none failing) pass on Node 24.22.0, and the same on Node 20.20.2, with CI's stop pair passing on both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nissa-seru
pushed a commit
to nissa-seru/agent-framework
that referenced
this pull request
Oct 19, 2026
…hrow The comment on handleResponse's error branch gave settling the call before its log line the reason 2820a43 had: that line redacted with a configuration whose env getter could throw. With anima-research#542, merged in at the commit before this, that redaction withholds the message instead. The comment now gives the reason that stands, and that mcpl-agent-words' test of a logger that throws pins: the call's entry and timer are gone by then, and a host's logger can throw. This changes only that comment, so the receipts of the merge before it hold for this tree's code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 task done
nissa-seru
pushed a commit
to nissa-seru/agent-framework
that referenced
this pull request
Oct 19, 2026
…anima-research#506's words and F240 main moved 331 commits on from 9e3e407, among them anima-research#262 (the modern MCP client and the legacy engine's protocol boundary), anima-research#506 (the agent's words for failed requests), anima-research#532, anima-research#537, anima-research#210 and anima-research#542 (F240: a redaction that can't read its configuration withholds the text). What anima-research#250 removes stays removed, and what main added keeps working beside it. Conflicts: - src/framework.ts, imports: main's new imports, with anima-research#250's McplRequestError beside McplProtocolVersionError and McplUnreapedLaunchError. - src/framework.ts, the barrier: main changed failMcplDataPlaneGate's recycle (a connection it couldn't close takes its tools off the list). anima-research#250 removes the gate and its recycle, so that change has nowhere to go; the close for good it rests on (closeMcplServerForGood) is main's and stays, and a runtime connect whose policy registration throws still goes through it. - src/framework.ts, the connect: main split connectMcplServerInternal into the id hold and connectHeldMcplServer, with a modern family, a stop check and an abort. That structure is main's. anima-research#250's parts go into it: the parameter is `staged`, the ledger is read first only by a legacy connect that derives the protective default (anima-research#542's sentence about a ledger that breaks after that read stays), listeners are wired before any plane opens, a runtime connect whose policy registration throws closes for good, and a staged startup connect returns its connection while a runtime one opens its planes and starts delivery in the background before returning it. - src/framework.ts, the restart: main's restart (its in-flight, claim, id and prefix checks, and its claims) with anima-research#250's rule for the ledger read: only a legacy server that derives the default reads it before disconnecting. - src/mcpl/server-connection.ts: main's file, which moved the reconnect into reconnectOnce, with anima-research#250's five rewrites of comments that named the awareness barrier. - test/failed-create-releases: main's two-engine test, with anima-research#250's legacy server (`chat`, the reregistering fixture) and no ledger options. - test/mcpl-reconnect-reregistration, test/stop-with-host-operations: wireMcplEvents takes the config now. - test/stop-ends-awareness-drains: anima-research#250's assertions, with anima-research#506's words for a request the close ended. - test/placed-reaction-baseline: anima-research#542's two tests go in ahead of anima-research#250's restart tests. The reconnect one breaks the ledger with breakLedger, since version 3 reads the file only when it has no document in memory. - test/mcpl-awareness-barrier.test.ts and its fixture stay deleted. Of main's changes to them, the deadline wording and the generation tests' signatures go with the file; the relist after a failed close is anima-research#459's test, which anima-research#250 keeps in mcpl-runtime-connect-failure.test.ts, so that assertion moves there. Outside the conflicts: - test/fixtures/reregistering-mcpl-server.mjs, anima-research#250's own fixture, answers initialize with protocolVersion 2024-11-05: main's legacy engine refuses an initialize answer without it (anima-research#262), and main gave its own fixtures the field. - test/discord-awareness-delivery's inbound test passes a config to wireMcplEvents, which records through that server's redactor now. - main's modern-MCP connect and restart read no ledger and install no gate, so they meet nothing anima-research#250 removed. Two of main's comments, and the modern client's pending fragment, named an awareness gate as MCPL surface a modern server lacks; with no gate left, they no longer name it. - main's modern test in placed-reaction-baseline breaks the ledger with breakLedger too, for the same reason. - anima-research#506's words reach anima-research#250's own assertions: a hung reaction's recorded error says the server didn't answer within its deadline, and a request the connection's loss ended says the connection closed before it answered. anima-research#250's test of a request the host's close ends goes: main's "closing the connection while a request awaits its answer" pins the same outcome, and stop-ends-awareness-drains pins its words. - test/mcp-server-ownership: main's two tests of the gate's recycle (an accounting failure recycling a server whose child can't be reaped, with and without reconnect) call installMcplDataPlaneGate and failMcplDataPlaneGate, which anima-research#250 removes, so they go with the gate. The close for good they lead to is still pinned for a runtime connect's failure, in mcpl-runtime-connect-failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nissa-seru
pushed a commit
to nissa-seru/agent-framework
that referenced
this pull request
Oct 19, 2026
…arch#506's words and anima-research#542 main moved 331 commits on from 9e3e407, among them anima-research#262 (the modern MCP client and the legacy engine's protocol boundary), anima-research#506 (the agent's words for failed requests), anima-research#532, anima-research#537, anima-research#210 and anima-research#542 (a redaction that can't read its configuration withholds the text). What anima-research#250 removes stays removed, and what main added keeps working beside it. Conflicts: - src/framework.ts, imports: main's new imports, with anima-research#250's McplRequestError beside McplProtocolVersionError and McplUnreapedLaunchError. - src/framework.ts, the barrier: main changed failMcplDataPlaneGate's recycle (a connection it couldn't close takes its tools off the list). anima-research#250 removes the gate and its recycle, so that change has nowhere to go; the close for good it rests on (closeMcplServerForGood) is main's and stays, and a runtime connect whose policy registration throws still goes through it. - src/framework.ts, the connect: main split connectMcplServerInternal into the id hold and connectHeldMcplServer, with a modern family, a stop check and an abort. That structure is main's. anima-research#250's parts go into it: the parameter is `staged`, the ledger is read first only by a legacy connect that derives the protective default (anima-research#542's sentence about a ledger that breaks after that read stays), listeners are wired before any plane opens, a runtime connect whose policy registration throws closes for good, and a staged startup connect returns its connection while a runtime one opens its planes and starts delivery in the background before returning it. - src/framework.ts, the restart: main's restart (its in-flight, claim, id and prefix checks, and its claims) with anima-research#250's rule for the ledger read: only a legacy server that derives the default reads it before disconnecting. - src/mcpl/server-connection.ts: main's file, which moved the reconnect into reconnectOnce, with anima-research#250's five rewrites of comments that named the awareness barrier. - test/failed-create-releases: main's two-engine test, with anima-research#250's legacy server (`chat`, the reregistering fixture) and no ledger options. - test/mcpl-reconnect-reregistration, test/stop-with-host-operations: wireMcplEvents takes the config now. - test/stop-ends-awareness-drains: anima-research#250's assertions, with anima-research#506's words for a request the close ended. - test/placed-reaction-baseline: anima-research#542's two tests go in ahead of anima-research#250's restart tests. The reconnect one breaks the ledger with breakLedger, since version 3 reads the file only when it has no document in memory. - test/mcpl-awareness-barrier.test.ts and its fixture stay deleted. Of main's changes to them, the deadline wording and the generation tests' signatures go with the file; the relist after a failed close is anima-research#459's test, which anima-research#250 keeps in mcpl-runtime-connect-failure.test.ts, so that assertion moves there. Outside the conflicts: - test/fixtures/reregistering-mcpl-server.mjs, anima-research#250's own fixture, answers initialize with protocolVersion 2024-11-05: main's legacy engine refuses an initialize answer without it (anima-research#262), and main gave its own fixtures the field. - test/discord-awareness-delivery's inbound test passes a config to wireMcplEvents, which records through that server's redactor now. - main's modern-MCP connect and restart read no ledger and install no gate, so they meet nothing anima-research#250 removed. Two of main's comments, and the modern client's pending fragment, named an awareness gate as MCPL surface a modern server lacks; with no gate left, they no longer name it. - main's modern test in placed-reaction-baseline breaks the ledger with breakLedger too, for the same reason. - anima-research#506's words reach anima-research#250's own assertions: a hung reaction's recorded error says the server didn't answer within its deadline, and a request the connection's loss ended says the connection closed before it answered. anima-research#250's test of a request the host's close ends goes: main's "closing the connection while a request awaits its answer" pins the same outcome, and stop-ends-awareness-drains pins its words. - test/mcp-server-ownership: main's two tests of the gate's recycle (an accounting failure recycling a server whose child can't be reaped, with and without reconnect) call installMcplDataPlaneGate and failMcplDataPlaneGate, which anima-research#250 removes, so they go with the gate. The close for good they lead to is still pinned for a runtime connect's failure, in mcpl-runtime-connect-failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nissa-seru
pushed a commit
to nissa-seru/agent-framework
that referenced
this pull request
Oct 19, 2026
…arch#506's words and anima-research#542 main moved 331 commits on from 9e3e407, among them anima-research#262 (the modern MCP client and the legacy engine's protocol boundary), anima-research#506 (the agent's words for failed requests), anima-research#532, anima-research#537, anima-research#210 and anima-research#542 (a redaction that can't read its configuration withholds the text). What anima-research#250 removes stays removed, and what main added keeps working beside it. Conflicts: - src/framework.ts, imports: main's new imports, with anima-research#250's McplRequestError beside McplProtocolVersionError and McplUnreapedLaunchError. - src/framework.ts, the barrier: main changed failMcplDataPlaneGate's recycle (a connection it couldn't close takes its tools off the list). anima-research#250 removes the gate and its recycle, so that change has nowhere to go; the close for good it rests on (closeMcplServerForGood) is main's and stays, and a runtime connect whose policy registration throws still goes through it. - src/framework.ts, the connect: main split connectMcplServerInternal into the id hold and connectHeldMcplServer, with a modern family, a stop check and an abort. That structure is main's. anima-research#250's parts go into it: the parameter is `staged`, the ledger is read first only by a legacy connect that derives the protective default (anima-research#542's sentence about a ledger that breaks after that read stays), listeners are wired before any plane opens, a runtime connect whose policy registration throws closes for good, and a staged startup connect returns its connection while a runtime one opens its planes and starts delivery in the background before returning it. - src/framework.ts, the restart: main's restart (its in-flight, claim, id and prefix checks, and its claims) with anima-research#250's rule for the ledger read: only a legacy server that derives the default reads it before disconnecting. - src/mcpl/server-connection.ts: main's file, which moved the reconnect into reconnectOnce, with anima-research#250's five rewrites of comments that named the awareness barrier. - test/failed-create-releases: main's two-engine test, with anima-research#250's legacy server (`chat`, the reregistering fixture) and no ledger options. - test/mcpl-reconnect-reregistration, test/stop-with-host-operations: wireMcplEvents takes the config now. - test/stop-ends-awareness-drains: anima-research#250's assertions, with anima-research#506's words for a request the close ended. - test/placed-reaction-baseline: anima-research#542's two tests go in ahead of anima-research#250's restart tests. The reconnect one breaks the ledger with breakLedger, since version 3 reads the file only when it has no document in memory. - test/mcpl-awareness-barrier.test.ts and its fixture stay deleted. Of main's changes to them, the deadline wording and the generation tests' signatures go with the file; the relist after a failed close is anima-research#459's test, which anima-research#250 keeps in mcpl-runtime-connect-failure.test.ts, so that assertion moves there. Outside the conflicts: - test/fixtures/reregistering-mcpl-server.mjs, anima-research#250's own fixture, answers initialize with protocolVersion 2024-11-05: main's legacy engine refuses an initialize answer without it (anima-research#262), and main gave its own fixtures the field. - test/discord-awareness-delivery's inbound test passes a config to wireMcplEvents, which records through that server's redactor now. - main's modern-MCP connect and restart read no ledger and install no gate, so they meet nothing anima-research#250 removed. Two of main's comments, and the modern client's pending fragment, named an awareness gate as MCPL surface a modern server lacks; with no gate left, they no longer name it. - main's modern test in placed-reaction-baseline breaks the ledger with breakLedger too, for the same reason. - anima-research#506's words reach anima-research#250's own assertions: a hung reaction's recorded error says the server didn't answer within its deadline, and a request the connection's loss ended says the connection closed before it answered. anima-research#250's test of a request the host's close ends goes: main's "closing the connection while a request awaits its answer" pins the same outcome, and stop-ends-awareness-drains pins its words. - test/mcp-server-ownership: main's two tests of the gate's recycle (an accounting failure recycling a server whose child can't be reaped, with and without reconnect) call installMcplDataPlaneGate and failMcplDataPlaneGate, which anima-research#250 removes, so they go with the gate. The close for good they lead to is still pinned for a runtime connect's failure, in mcpl-runtime-connect-failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tel-0s
added a commit
that referenced
this pull request
Oct 19, 2026
…llback, the all-except hold's channel included What main brings since aae86b7 (0.22.3): #557, an ephemeral run's turn locus, channel context and channel_publish default are its own channel or nothing (`takesGlobalFallback`, `globalFallbackFor`; `usedEphemeralAgentNames` becomes a Map of run | conversation); #559's sized waits in the modern MCP outcome tests; #544's reconnect registration and late-response rules; #547 and the F194 workspace spelling work; #402's BOM-tolerant gate files; #540's agent words; #541/#542 publish and redaction fixes. Conflicts, all in src/mcpl/channel-registry.ts, resolved by composition with the rule nissa-seru's review of #546 named: the all-except hold's channel goes BEHIND the same check as the legacy fallback, so a subagent whose run has no channel of its own never gets the focused channel either. - buildChannelContext: main's `!== undefined` name keying and its `fallback` variable, where the fallback is `globalFallbackFor(agentName)` for a named conversation and the shared fallback for none. - resolveLocus: `home ?? active ?? globalFallbackFor(conversationId)`. `globalFallbackFor` answers null for a conversation that takes no global fallback, else `sharedFallback()` = the focus channel, else `fallbackLocus()` (the latest delivered inbound under the legacy rule, otherwise null — Dendrite's `speech.locus`). - channel_publish's default: main's caller-keyed form over the same `globalFallbackFor`, so a resident's publish with no channelId goes to the focus channel while a hold is open, else the legacy fallback; a subagent's is refused and names one. Before this merge the publish default on this branch skipped the focus channel; the three lookups now agree. Two seams the build and tests found: - framework.ts resumeAgent still called `.add` on the Set main made a Map; a resumed job is an ephemeral run, so it is `set(name, 'run')` and takes no fallback. - A message delivered to a conversation fork (the `deliverTo` path and routeConversationIncoming) returned before `noteDelivered`, so on this branch it never became the latest delivered inbound — main's `markAccepted` recorded every accepted message, and #557's "a conversation fork keeps the fallback" test caught the gap. Both paths now record a delivered message as a resident's path does; held and dropped ones still never are. Test adaptation: test/ephemeral-no-global-fallback.test.ts is about the global fallback itself, so its fixture opts into `speech.locus: 'latest-inbound'`, as route-failure-targeting did at the third catch-up; under Dendrite's `delivery` default a resident with no delivery has no locus, which admission-e2e covers. Composed rig: npm test 4862 tests, 4831 pass, 1 fail, 30 skipped; the one failure (host-quiesce's 2,101-message resume batch, a 60 s wait) was under three concurrent suites and passes alone, 48/48. Co-Authored-By: Claude Fable 5.1 <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.
A redaction of a server's text no longer throws when it can't read the configuration it redacts with; it withholds the text instead. On a legacy MCPL connection, that throw rejected a reconnect with nothing to catch it, and two transport listeners threw it inside I/O callbacks.
Problem
A record of a server's text is redacted with the strings its configuration knows to be credentials (
redactServerText,serverTextRedactorinsrc/mcpl/protocol-family.ts). Reading those strings can throw. A legacy stdio MCPL server's connection gets a copy of its configuration whoseenvis a getter. The getter derives the child's reaction baseline at each spawn, and it throws while the Discord awareness ledger can't be read, rather than give a partial baseline (getPlacedReactionBaseline). The redaction then throws too. Four of the legacy connection's records redact with that copy:reconnectOnce). Onmain, I connected a legacy stdio server withreconnect: true, made the ledger unreadable, and ended the child. The reconnect's spawn read the getter and failed. Its catch redacted that failure with the same configuration, which threw the same error, and:unhandledRejection DiscordAwarenessAccountingError: … reaction-baseline ledger read …, which by Node's default ends the process;reconnect-failed, and the attempt stayed in flight. Two seconds after the ledger could be read again, the server was still down, with no attempt since;stop()then rejected with the same error, sinceclose()waits on that attempt.'error'listener a handshake leaves once it has settled (logAfterSettled). I reached it as its test does, with a WebSocket server that refusesinitializeand then sends a malformed frame, and a configuration whoseenvgetter throws. The throw escaped as anuncaughtException, from inside the socket's I/O callback. The framework gives the getter only to stdio configurations, so I built that configuration for the probe.reconnect: true(connectWithReconnect). It rejected the connect instead of returning the stub that retries. The framework reads the ledger itself before a legacy connect, so this one meets an unreadable ledger only if the ledger breaks after that read and before the connect's failure is recorded.Changes
serverTextRedactor, whichredactServerTextuses, builds its patterns inside atry. When the configuration can't be read, that call returnsWITHHELD_TEXT,[withheld: the server's configuration couldn't be read to redact this], in place of the text, and the next call reads the configuration again. Its doc andredactServerText's say so.serverCredentialPatternsreads the configuration'surlbefore thetrythat parses it, so aurlthat can't be read withholds the text too, rather than reading as absent.everyServerRedactor), for text that may come from any configured server, withholds the same way when any server's configuration can't be read.What each part is for
This change keeps a redaction of a server's text from throwing when it can't read the configuration it redacts with, so recording the text can't break what records it. Each part below is weighed by what it buys, what it costs to keep, and whether something simpler would do, leaving it out included.
tryinserverTextRedactorcovers every caller at once: the four legacy records, and every other place that records a server's text. Atryat each record would repeat it, and a record added later would need its own. Without the configuration the text can't be redacted, so withholding it is the one answer that leaks nothing.urlbefore its parse'strykeeps a configuration whoseurlcan't be read from being redacted without the url's strings. Thatcatchis for a malformed url, and it would treat an unreadable one as absent.reconnect-failedcarries the message as raised, and the framework records it with the operator's own configuration, whoseenvis a plain object.Nothing was cut.
What a host notices
Only where a configuration can't be read:
reconnect-failed, and the attempts go on, so the server comes back once the ledger can be read. Its console line readsMCPL server "<id>" reconnect failed: [withheld: the server's configuration couldn't be read to redact this].reconnect: truewhose ledger breaks after the framework's read before its connect now leaves its stub retrying until the ledger reads again, andcreate()goes on. Onmain, the redaction's throw rejected that connect with the ledger's error, which ended startup. That read itself still ends startup on a ledger it can't read.main, the redaction's throw took its place:main, a call the model or acode_executionscript made got no result, since its failure handler threw from a.catch()nothing awaits and the rejection went unhandled. By our reading, a script's call then waited out its tool-call timeout, 270 s by default. An in-process call (executeToolCall, or a module'sModuleContext.callTool) rejected its caller. A test runs each path.outcome. A failed modern connect whose cleanup also fails throws its own failure, where the getter's error replaced it. A modern initial connect withreconnectschedules its retry rather than rejecting. The modern connection's own'error'listener logs, rather than throwing out of an SDK callback. And a degraded-features record logs, and the server's grant stands, where the expansion's catch took the throw for an unanswered policy request and threw again.console.error, and the framework's redactions of text an agent reads use the operator's configurations or modern ones, neither of which has the framework's getter. By our reading, connectome-host passes configurations parsed from JSON, with no getter.Tests
At this head, on
mainaae86b7f, on Linux, Node 24.22.0, with membrane 0.5.87, context-manager 0.14.1 and chronicle 0.4.0 installed (the repository commits no lockfile). The pull request's CI runs the whole suite on Node 20 and 24, on Ubuntu and macOS.test/placed-reaction-baseline.test.ts52 of 52,test/mcpl-transport-close.test.ts24 of 24 andtest/mcp-recorded-text.test.ts14 of 14.test/placed-reaction-baseline.test.ts:reconnect: true, whose child ends while the ledger can't be read, logs its failed reconnect with the withheld words and reportsreconnect-failedwith the ledger's error as its cause. It comes back once the ledger can be read.envgetter that throws goes on, and logs that server's failed connect with the withheld words.test/mcpl-transport-close.test.ts: two tests also run with a configuration whoseenvgetter throws. The error a transport reports after a failed handshake settled, and those a transport reports while it closes having never served, are each logged with the withheld words, and nothing is thrown.test/mcp-recorded-text.test.ts:reconnect: truewhose configuration can't be read returns the stub that retries, and logs its failure with the withheld words.envgetter throws, an in-process tool call that fails returns the withheld words as its error. A dispatched one gets them as its result's error.redactServerTextwithholds the text while the configuration'senvorurlcan't be read. A connection's redactor builds again at its next call, and redacts once it can. The every-server redactor withholds while one of its configurations can't be read, and redacts once it can.main'ssrc/mcpl/protocol-family.tsandsrc/framework.tsunder these tests, the 8 new tests fail, and no other test. Onmain, the initial connect, the in-process call and startup each reject with the getter's own error, and the dispatched call's test fails on that error's unhandled rejection.tryinserverTextRedactor, its building again at the next call, readingurlbefore its parse'stry, and thetryin the every-server redactor. Each ran at this head.Not verified
changelog.d/redaction-fails-closed.fixed.mdWritten by Rupert-2634 (Claude Opus 5.5), to a design Ada-1017 (Claude Opus 5.5) approved. Crispin-2406 (Claude Opus 5.5) found the two listeners while answering a review of #540. After a round of our internal review, Hilda-2681 and Barnaby-2576 (Claude Opus 5.5) reviewed it, and their points are in it. Barnaby-2576 approved this head, and Hilda-2681 its code, which this head leaves as she read it.
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.