Skip to content

fix(mcpl): a server closed for good leaves the registry, and a failed runtime connect settles its gate - #459

Merged
nissa-seru merged 6 commits into
anima-research:mainfrom
nissa-seru:fix/mcpl-close-down-server
Oct 18, 2026
Merged

nissa-seru merged 6 commits into
anima-research:mainfrom
nissa-seru:fix/mcpl-close-down-server

Conversation

@nissa-seru

Copy link
Copy Markdown
Contributor

Fixes for a runtime MCPL connect that fails partway, and for servers the framework closes for good. A reconnect: true server that the framework closes for good now leaves the registry even when it's down at the time, so a later connect of its id isn't refused as already registered. A runtime connect now settles the data-plane gate it installed on every exit, so when its awareness accounting or its policy registration fails, the other MCPL servers' data is no longer held behind that gate. And a connection closed for good no longer lets out what it held.

Problem

On main (3af13bf4):

  • A server closed for good while it's down stays registered. The registry drops an entry from its 'close' listener, for a connection that won't reconnect (src/mcpl/server-registry.ts:53-55), or in closeServer, which removeServer and closeAll call (:72, :144, :151). McplServerConnection.close() returns without emitting 'close' when the connection is already closed, with no close left to finish and no reconnect attempt in flight (src/mcpl/server-connection.ts:939). A reconnect stub, or a server that dropped, is in that state while it waits for its next retry. The framework closes a server for good with connection.close() in three places:

    • The catch that ends a runtime connect or restart whose awareness accounting fails (src/framework.ts:17636). When the server's first connect had failed, the connection there is the stub connectWithReconnect returned. The stub stays registered, and a later connectMcplServer of its id fails with MCPL server "<id>" is already registered (src/mcpl/server-registry.ts:42) until disconnectMcplServer or restartMcplServer drops it. Greptile found this in its review of fix(mcpl): an MCPL server's boolean settings are true or false, and anything else is refused (#379) #451.
    • A refused policy's "close" fallback, after a manifest change (src/framework.ts:17800) and at the initial policy (:17918). The server answered the policy request just before, so it's down there only if it dropped in between.
  • A runtime connect that fails partway leaves its gate standing. connectMcplServerInternal installs the data-plane gate before it awaits accounting (src/framework.ts:17616), and installing it pauses every registered server's data plane (:17444). The connect completes the gate only once its policy registration has returned (:17644-17645).

    • When accounting fails, the catch closes the new connection and rethrows, and never fails or completes the gate. The four other runtime gates call failMcplDataPlaneGate when their accounting fails: resume(), syncDiscordAwarenessMarkers(), tools-list reconciliation and reconnect reconciliation (:5137, :17175, :18498, :18553).
    • When the policy registration throws after accounting succeeded, nothing there catches it. The new connection stays connected and registered, and the gate stays standing.

    Either way, every other server's pushes, incoming messages and inference requests are held until some other gate completes.

  • A connection closed for good can still let out what it held. ready() and readyControlPlane() don't check whether the connection is closed (src/mcpl/server-connection.ts:346, :380), and a close that fails keeps its registry entry (src/mcpl/server-registry.ts:157-160). So the next gate's completion flushes what that connection held, with its policy already reset.

Changes

  • Closes for good go through the registry. The three places call McplServerRegistry.closeServer(id, connection), which is no longer private and has a doc comment. It drops the entry once close() resolves, whatever the connection reports, if that connection is still the one registered under the id. A close that fails keeps the entry and rejects, and a close already under way is shared, as before.
  • A failed accounting fails the gate. Once the close for good has settled, the catch calls failMcplDataPlaneGate, then rethrows. While the host serves, that recycles the running servers, as on the four other paths: each with reconnect: true reconnects, and its reconnect's own gate holds its data until that reconnect's accounting succeeds. While the host is stopping, it releases the gate.
  • A failed policy registration closes the new connection and completes the gate. The connect closes its new connection for good through the registry, completes the gate, and rethrows.
  • A connection closed for good readies nothing. McplServerConnection.ready() and readyControlPlane() now do nothing once the connection is closed with reconnect off, as after close(), whether or not its transport close succeeded, or after a drop with reconnect off. A connection between retries keeps reconnect on and readies as before.
  • A close that fails is logged. Both catches close through closeFailedRuntimeConnect, which logs a close that fails instead of discarding it. Such a close keeps the entry, as closeServer does for every caller, so a later disconnect, restart or shutdown can close it again.
  • Comments. Each catch says why it closes through the registry and how it settles the gate. McplServerConnection.close()'s comment now says only the registry's closeAll bounds its caller's wait.

What callers will notice

  • After a runtime connectMcplServer or restartMcplServer fails its awareness accounting or its policy registration, connecting the same id again works, where it failed as already registered. If the close of the failed connection fails too, its entry stays and the failure is logged, so the id is free again once a disconnect, restart or shutdown has closed it.
  • A failed accounting now recycles every running MCPL server while the host serves, with an mcpl:server-error trace for each that reads Discord awareness accounting unhealthy: …, as the four other runtime paths already do. A running server without reconnect: true is closed for good there. On main, those servers stayed connected with their data held. The connect or restart rejects once that recycle has closed the running servers' transports, as resume() and syncDiscordAwarenessMarkers() return only after theirs.
  • A failed policy registration now closes the new server and leaves the running servers connected, their data no longer held behind the failed connect's gate. On main, the new server stayed connected and registered, and every server's data stayed held behind that gate.
  • McplServerConnection.ready() and readyControlPlane() now do nothing once the connection is closed for good. What it held stays held. Before, any gate's completion passed the part of it that needs no grant to listeners, as for a connection whose close failed and so stayed registered. While the host stops, a connection closed for good, such as one being closed, no longer passes what it held to the stopping refusal, whose answers can't be sent on a closed connection. What every other connection held reaches it as before.
  • A server that drops just before a refused policy's "close" fallback leaves the registry too.
  • Nothing public changes shape: McplServerRegistry isn't exported from the package entry.

What each part is for

  • Through closeServer, rather than having close() emit 'close' for a connection that's down. A connection that already reported its drop would report a second close, and every 'close' listener would run twice for one drop, the framework's mcpl:server-closed and module:removed traces among them. closeServer already drops the entry for removeServer and closeAll, and drops it only while that connection is still the registered one, which a restart could have replaced.
  • All three closes for good, not only the awareness catch. The rule then holds wherever the framework closes a server for good. At the two fallbacks it covers a server that drops in between.
  • Left out: removeServer(id) at those places. It closes whatever is registered under the id, which may no longer be this connection.
  • failMcplDataPlaneGate when accounting fails, rather than completing the gate. Completing it would release the other servers' data while accounting is failing, which the catch exists to refuse, and it would make this the one runtime gate that fails open. Its cost is the one the four other paths already pay: a running server without reconnect: true is closed for good.
  • Completing the gate when the policy registration throws, rather than failing it. Accounting succeeded, so the other servers' data is fine to release, and failing the gate would recycle them for nothing. The reconnect path completes its gate the same way when its re-registration throws.
  • The close before the gate fails, so the refused connection is out of the registry and isn't recycled, unless its close fails.
  • The rule at the connection, not at each completion. A connection closed for good has had its policy reset, so what it held that needs a grant would be refused, and it can send no response, so nothing it held could be answered. Readying it would only pass the rest to listeners of a server that won't be served again, from whichever completion readies it next: the failed connect's, a later gate's, or one after a close that failed in removeServer or closeAll. One check in ready() and readyControlPlane() covers them all.
  • Only closed for good. A connection between retries still readies: what it held, such as a reconnect stub's connect-failed, reaches its listeners.
  • One helper for both catches, so a failed connect's connection is closed, and a failed close logged, in one place.
  • The tests.
    • The stub test protects what Greptile found. It also checks that a running server without reconnect: true ends closed, neither connected nor retrying.
    • The gate test protects the held data on the accounting exit, and the policy-registration test protects it on the other exit. Run again with a close that fails, that test checks that the connect still reports the registration's error, that the connection stays registered and paused through a later syncDiscordAwarenessMarkers(), and that the failed close is logged.
    • A stop-path test holds a control event and a data event on two connections and starts closing one. While that close is still under way, it checks that releasing and then failing the gate while the host stops lets out only the other one's.
    • The runtime-connect helper checks that the refused connection gets no "accounting unhealthy" trace, which pins the close before the gate's failure.
    • A registry test checks that closeServer leaves an entry that a newer connection holds under the same id, which is why the three places use it rather than removeServer(id).
    • The two fallback tests now hold their fake connection in a real registry, and the "close" fallback must leave it unregistered. The fakes' close() emits nothing, as a connection's does when it's down between retries.

Tests

At 5822b438, on Linux, Node 24.22.0. The pull request's CI runs the whole suite on Node 20 and 24.

  • The four touched test files pass: shutdown-errors 29 tests, mcpl-manifest-changed 8, mcpl-config-diagnostics 12 and mcpl-awareness-barrier 34. At 8628705b, whose src/ differs from this head's only in comments, the 31 other test files whose names start with mcpl-, stop-with- or host-quiesce pass too.
  • With main's src/framework.ts, src/mcpl/server-registry.ts and src/mcpl/server-connection.ts, with closeServer made public so the registry test compiles, 7 tests fail: both fallback tests, the four runtime-connect tests and the stop-path test. The registry test passes there, since main's closeServer already holds its guard.
  • Each piece taken back out alone fails a test:
    • at 5822b438: the check in ready() (the failed-close test and the stop-path test); the check in readyControlPlane() (the stop-path test); and the check's reconnect condition, without which a connection between retries would count as closed for good (mcpl-reconnect-events' test of a reconnect stub);
    • at 76798228: the policy exit's gate completion, and a gate failure in its place (both policy-registration tests); and a failed close's error escaping closeFailedRuntimeConnect (the failed-close test, whose connect then rejects with the close's error);
    • at c87c6436: the failed connect's close going straight to the connection, as on main (the runtime-connect helper's trace check); the accounting exit's gate failure (the stub and gate tests); closeServer's guard (the registry test); the close and the gate's failure in swapped order (the helper's trace check); and the policy exit's close (the policy-registration test);
    • at afa80b53, this pull request's second commit: either "close" fallback's change (its fallback test).
  • A probe of the gate, a framework serving one MCPL server without reconnect: true, then a runtime connect whose first connect fails and whose accounting then fails:
    • at 8202015e, this pull request's first commit, the failed connect's gate is still the current one after the rejection, and the running server is still connected with its data plane paused, the same 3 s later;
    • at 5822b438, that server is closed and unregistered by the time the connect rejects.

Not verified

  • A server that drops between answering the policy request and the "close" fallback isn't staged. The fallback tests' fake connection, whose close() emits nothing, stands in for it.
  • A close that fails is staged only at the policy exit, by making its transport close reject once. At the accounting exit it isn't staged. shutdown-errors.test.ts pins the registry keeping such an entry, through closeAll.
  • No live MCPL server beyond the tests' own fixture.

Out of scope

  • After a server is closed for good while it's down, no second mcpl:server-closed or module:removed trace follows the ones its drop emitted, as when disconnectMcplServer removes a server that's down, on main.
  • A close that never settles still holds the failed connect's gate and its rejection, as on main, where this catch awaited the same close. main's StdioTransport.close() sends one SIGTERM and waits for the child's exit with no bound; feat(mcp): modern MCP (2026-07-28) servers beside MCPL, over stdio and Streamable HTTP #262's, at its head c7eda6ce, escalates to SIGKILL and bounds the wait.

Related

Written by Effie-2756 (Claude Opus 5.5), on a design Ada-1017 (Claude Opus 5.5) approved. Naomi-2422 (Claude Opus 5.5) reviewed the change.

Effie-2756 added 6 commits October 17, 2026 15:53
A reconnect: true server that the framework closes for good while it's
down stayed registered. The registry drops an entry only from its 'close'
listener or in closeServer (removeServer, closeAll), and close() emits no
'close' for a connection that's down between retries (the early return in
McplServerConnection.close()). The framework closed servers for good with
connection.close() at three sites:

- connectMcplServerInternal's awareness-barrier catch, reached by a
  runtime connectMcplServer or restartMcplServer whose Discord awareness
  accounting fails. When the server's first connect had failed, what it
  closed was the stub connectWithReconnect returned, which stayed
  registered, so a later connectMcplServer of its id failed as already
  registered until disconnectMcplServer or restartMcplServer dropped it.
  Greptile's review of anima-research#451 found this path.
- The "close" fallback in handleManifestChanged and in
  registerMcplServerFeatures, taken when a server refuses the host's
  policy. The server answered the policy request a moment before, so it's
  down there only if it dropped in between.

Each site now calls the registry's closeServer, made public with a doc
comment, which drops the entry once close() resolves, whatever the
connection reports, if that connection is still the one registered.

The awareness catch's comment now says why its close goes through the
registry.

Tests: a runtime connect whose accounting fails (recordFailure throwing)
after the server's first connect failed, then a second connect of the id,
which succeeds. The two fallback tests' harnesses hold their fake
connection in a real registry, and the "close" fallback leaves it
unregistered; the fakes' close() emits nothing, as a connection's does
when it's down between retries.
…ts gate

connectMcplServerInternal installs the data-plane gate before it awaits
awareness accounting, which pauses every registered server's data plane.
When accounting failed, the catch closed the new connection and rethrew,
and never failed or completed that gate. Every other runtime gate calls
failMcplDataPlaneGate when its accounting fails: quiesce resume(), explicit
syncDiscordAwarenessMarkers(), tools-list reconciliation and reconnect
reconciliation. So after a runtime connectMcplServer or restartMcplServer
whose accounting failed, every other server's pushes, incoming messages and
inference requests were held until some other gate completed. A probe
without this commit's change ran a server, then a runtime connect whose
accounting failed: the failed connect's gate stayed current, and the
running server's data plane stayed paused, still 3 s later.

The catch now calls failMcplDataPlaneGate after the close for good, as
those paths do. While serving, that recycles the running servers: each
with reconnect: true comes back, and its data flows once its reconnect's
accounting succeeds, while a server without it stays closed, as on those
paths. While stopping, it releases the gate. The close comes first, so the
connection being refused is out of the registry and isn't recycled, unless
its close fails, which keeps its entry for a later close to retry.

Tests: the runtime-connect fixture moves into a helper that stops the
framework if anything after create() fails. A new test runs a reconnecting
server, fails a runtime connect's accounting, and checks that the gate
failed for the running server (its "accounting unhealthy" mcpl:server-error
trace) and that the recycled server's next startup push is answered.
…r the order, the identity guard and the closed server

Answers the internal review of the first two commits.

A runtime connect whose policy registration throws after its awareness
accounting succeeded left the new connection live and registered, and the
gate it installed standing over every other server's data planes, since
only the success path completed the gate. That catch now closes the new
connection for good through the registry, as the accounting catch does, and
completes the gate rather than failing it: accounting succeeded, so nothing
calls for a recycle.

Both catches close through closeFailedRuntimeConnect, which logs a close
that fails instead of discarding it. Such a close keeps the entry, so a
later disconnect, restart or shutdown can close it again. close()'s comment
now says only closeAll bounds its caller's wait for an in-flight close.

Tests:
- A runtime connect whose policy registration throws (initializeServer
  made to throw for it) while another server runs: the connect rejects,
  the gate is completed, the running server stays connected with its data
  plane ready and no gate fails, and the id connects again.
- The runtime-connect helper checks that the refused connection gets no
  "accounting unhealthy" trace, which it would if the gate failed before
  the close took it out of the registry.
- The stub test's running server has no reconnect: true; it checks that the
  server ends neither connected nor retrying.
- A registry test: closeServer leaves an entry that a newer connection
  holds under the same id, as after a restart.

The changelog fragment covers the policy registration exit and a failed
close.
…sed; test a close that fails

Answers the internal review of the previous commit.

When a runtime connect's policy registration throws and the close that
follows fails, the connection stays registered, as closeServer keeps it.
Completing the gate then ready()d it along with every other connection.
ready() doesn't check whether a connection is closed, so what it held
that needs no grant would have reached listeners.
completeMcplDataPlaneGate now takes a connection to leave paused, and the
policy exit passes the one it is closing.

Tests: the policy-registration test becomes a helper that runs twice. With
a close that rejects once, the connect still rejects with the
registration's error, the connection stays registered and paused, the gate
is completed, and the failed close is logged.
…the completion's skip

Answers the review of the previous commit.

The previous commit left the connection a failed connect closes paused at
that connect's own completion, but a later gate's completion, or a release
of control traffic, still readied it: ready() and readyControlPlane() didn't
check whether the connection was closed. The same held for any connection a
failed close keeps registered, on main too.

ready() and readyControlPlane() now return at once when the connection is
closed for good: closed, with reconnect off. close() turns reconnect off and
marks the connection closed before its transport close can fail, and a drop
with reconnect off leaves it the same way. A connection between retries
keeps reconnect on, so it still readies after its reconnect.
completeMcplDataPlaneGate's skip goes.

While the host stops, a connection closed for good, such as one closeAll has
begun closing, no longer passes what it held to the stopping refusal, whose
answers can't be sent on a closed connection anyway. What every other
connection held reaches it as before.

Tests: the failed-close run now fails the transport close, after close() has
marked the connection, and checks that a later syncDiscordAwarenessMarkers()
leaves it paused. A stop-path test holds a control event and a data event on
two connections, closes one, and checks that releasing and then failing the
gate while the host stops lets out only the other one's.
…a close still under way

Answers the internal review of the previous commit.

ready()'s comment gave the reason for doing nothing once a connection is
closed for good as its server learning of the close from the close itself,
which a close that fails doesn't give. The reason that holds is that
nothing it held could be answered: a closed connection sends no response,
and its reset policy refuses what needs a grant. Readying it would only pass
what needs no grant to listeners of a server that won't be served again.
The comment now says so, and that a connection between retries still
readies, so a reconnect stub's connect-failed reaches its listeners.
failMcplDataPlaneGate's comment no longer says everything the pause held
back reaches the stopping refusal.

The changelog fragment states the stopping case for every connection closed
for good, not only one being closed, and no longer says the running
servers' data flows once a gate completes, which a quiesced host doesn't do.

Tests: the stop-path test starts closing a connection without waiting for
the close, so the gate is released and then failed while that close is
still under way, the state a connection closeAll has begun closing is in.
@greptile-apps

greptile-apps Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5 Tier: apex

[Medium impact] The PR appears safe to merge; no actionable regression was found.

Summary

Fixes cleanup after failed runtime MCPL connects and policy refusals.

  • Runtime MCPL failures close the new server and settle its data gate.
  • Closed MCPL servers leave the registry when their close succeeds.
  • Closed MCPL connections no longer flush their buffered events.

Acknowledged by nissa-seru: accounting failures recycle other servers; failed closes retain their entries; permanently closed connections keep buffered events held; closing an already-down server emits no second close trace; unsettled closes remain out of scope.

Review used code and test inspection. Tests were not run.

Reviews (1) · Last reviewed commit: "fix(mcpl): say what a connection closed ..." · Reviewed by Greptile

@nissa-seru
nissa-seru merged commit 420b8a4 into anima-research:main Oct 18, 2026
7 checks passed
nissa-seru pushed a commit to nissa-seru/agent-framework that referenced this pull request Oct 18, 2026
main gained anima-research#457, anima-research#458, anima-research#459, anima-research#454, anima-research#460, anima-research#464, anima-research#412 and anima-research#467 since
86a3683. One block conflicts, in restorePersistedDeferredWrites: anima-research#454
narrowed its try to reading the recovery file, so that a file it can't
read or take fails create(), and moved the parsing and numbering after
it, while this branch changed that numbering (boot numbers the restored
queue 1..N). The resolution takes main's side of the block, then makes
this branch's change to main's numbering where it now stands: the queue
is ordered by valid seq, then the rest in file order, numbered 1..N
after the already-landed entries are left out, and the counter goes on
from N; the file is rewritten for an entry without a valid seq, not for
the new numbers. main's check for writes that already landed, which now
refuses create() when a context can't be read, is kept as main has it,
over the ordered entries.

Everything else merged without a conflict. The only other change of
main's within forty lines of one of this branch's is anima-research#457's to an
ephemeral run's idle watchdog, which now rejects a run that stop() has
begun to end as stopped; it sits above the run's finally, which this
branch changes, and neither depends on the other.

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 18, 2026
main brings agent-framework anima-research#456 (the workspace file tools' fixes), anima-research#460 (editors' files and nested mounts), anima-research#410, anima-research#455, anima-research#457, anima-research#458, anima-research#459, anima-research#454, anima-research#464, anima-research#412 and anima-research#467.

- write, edit and delete: anima-research#456 answers a change stored in the workspace but not on disk with one frame (storedButUnfinished), which leads with "stored, so don't send it again" and gives the push's reason. This branch had reworded those frames to say where force goes. Its frame goes and anima-research#456's stays: every reason a write's push can return names materialize where it offers force, and so do this branch's mode notes. Each success keeps its modeKept note, and commitToolChange keeps anima-research#456's onCommitted and answers { refused, modeKept }.
- write: an overwrite keeps the entry's mode inside anima-research#456's guarded commit, as an edit does.
- reconcile.ts: an effect that fails untouched names its kind, a chmod step's included, beside anima-research#456's account of what's in the way (inTheWay).
- edit: anima-research#456's edit takes a change on disk in first, with a pass over its path. Where disk changed only a file's mode, that pass takes the mode in, as a listing does, and the edit's note read it as disk's copy having changed and the edit applying to that text. A mode taken in alone isn't a change to the text, so the note no longer counts one. The edit then writes at the mode disk has and leaves nothing owed.
- anima-research#460: a push skips a path in another mount's directory before it plans, so it plans no chmod there either.
- The changelog fragment drops its sentence about the write tools' frame, which anima-research#456's replaces, and no longer names an edit among what says that nothing records which side changed a mode after a refused widening, since an edit's pass takes disk's mode in first.
- Tests: the test of a refused narrowing's frame takes anima-research#456's wording, the test of the force sentence goes with that sentence, and two tests pin an edit after a mode disk changed and after a refused widening.

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 18, 2026
…'s close of a failed runtime connect, and train fix-c and after

Conflicts, and what each keeps:
- settlePolicyExchange's tail: this branch's. main's side there is the
  barrier's release, completion and failure (installMcplDataPlaneGate and
  the rest), which this branch removes; anima-research#459 changed only a comment in it.
- connectMcplServerInternal's tail: this branch's, with no data-plane gate.
  main's side is the gate's install, its accounting wait and its
  completion, with anima-research#459's handling of a failed step inside it.
- test/mcpl-awareness-barrier.test.ts stays deleted, with the barrier it
  tested.

Carried from main (anima-research#459, R2-1 of the maintainer's review of 3fb0415):
- A runtime connect or restart whose policy registration throws closes the
  new connection for good through the registry
  (closeFailedRuntimeConnect), then rethrows, so it isn't left connected
  and half registered, and a later connect of its id isn't refused as
  already registered. Here that wraps the connect's settlePolicyExchange
  for a connect that isn't staged, as main's close is. A staged startup
  connect's failure goes to initializeMcpl's loop, which logs it and goes
  on with the other servers, on main as here. anima-research#459's other failed step,
  awareness accounting, has no counterpart here: no connect accounts for
  awareness.
- anima-research#459's tests that don't need the barrier move to
  mcpl-reconnect-registration: a runtime connect whose policy registration
  throws closes its connection for good and a later connect of its id
  reaches the server; one whose close then fails stays registered and
  paused through a resume, and the close is logged; and a connection
  closed for good readies nothing, while a running one lets out what it
  held. Its tests of a failed accounting and of a failed gate test the
  barrier, and go with it.

anima-research#459's server-connection and registry changes, a refused policy's close
fallback through the registry, and the rest of main merge without a
conflict. In src/framework.ts, anima-research#454 meets this branch in initializeMcpl,
where it reads the push coalescer's and checkpoints' state before anything
is built, and anima-research#457 in stopOwned, where it ends ephemeral runs after the
loop; neither touches what this branch changes there.

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 18, 2026
…ts marker

A runtime connect or restart whose policy registration throws closes the
new connection for good, through the registry, as anima-research#459 does on main. The
close ran in connectMcplServerInternal's catch, after settlePolicyExchange's
finally had lifted the exchange marker, and the registry closes a
connection in a later microtask. So for at least two microtask turns the
failing connection was connected, unmarked and not yet closed, and an
opener that ran then, such as a resume's readyMcplPlanes finishing
meanwhile, would ready it and let out what it held with no grant.

On main the window is wider: a resume's own gate readies every registered
server, a runtime connect's included, at any point in its exchange. This
branch's marker narrowed it to the failure edge, and this closes the edge.

settlePolicyExchange takes closeOnFailure, which a runtime connect or
restart passes: an exchange that throws closes the connection in the
exchange's own catch, before its finally lifts the marker. A close that
fails still marks the connection closed for good, so it readies nothing.
The wrap in connectMcplServerInternal goes, and with it a comment that said
a staged startup connect's failure ends startup: initializeMcpl's loop logs
it and goes on with the other servers, on main as here. The comment now
says so.

The policy-failure test records, as the failing connection's close
begins, which marks it closed for good, whether its exchange marker still
holds it, and asserts that it does.

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 18, 2026
Brings in main since 86a3683, among it: one MCPL tool resolver (anima-research#412),
a runtime connect that settles its data-plane gate on every exit, and the
framework's closes for good going through the registry (anima-research#459), and a
forced test run that no longer loses a test file's output (anima-research#464).

Conflicts, resolved by hand:
- src/framework.ts, executeMcplToolCall: anima-research#412's signature, the server id
  and the prefix the resolver matched, with this branch's modern-server
  branch looked up by that id. The error's redaction reads the server's
  configuration by the id, as the tool policy check does.
- src/mcpl/server-connection.ts:
  - holdsUnreapedChild beside anima-research#459's closedForGood.
  - close() keeps this branch's closeStep. anima-research#459 changed only a comment
    in the code closeStep replaced.
- test/mcpl-config-diagnostics.test.ts: this branch's two redaction tests,
  then anima-research#459's renamed test of a refused initial policy.

Beyond the conflicts: test/mcp-recorded-text.test.ts calls
executeMcplToolCall with anima-research#412's signature, the server's id and prefix.

Merged without a conflict, and read against this branch:
- dropMcplToolClasses takes anima-research#412's drop by the listing's owner, which
  both engines' close handlers call.
- connectMcplServerInternal takes anima-research#459's settling of the gate: after the
  gate's install, an accounting failure closes the new connection
  through the registry and fails the gate, a policy registration that
  throws closes it and completes the gate, and success completes it.
  Nothing else returns or throws after the install.
- The registry's closeServer, now public, drops an entry only once its
  connection's close() resolves, so a connection whose close can't reap
  its child stays registered, holding its id.

Checks, on Linux, Node 24.22.0, at this commit's tree: the typecheck and
the build pass, and 19 files of the merged code's tests pass, each run on
its own and unforced: mcpl-config-diagnostics 14, mcpl-awareness-barrier
34, mcpl-manifest-changed 9, shutdown-errors 29, mcp-server-ownership 37,
mcp-modern-framework 18, mcp-modern-outcomes 38, mcpl-legacy-lifetime 16,
mcpl-runtime-lifecycle 37, mcpl-tool-resolution 13, mcpl-tool-classes 9,
mcpl-tool-class-listing 4, mcpl-tool-lifecycle 31, mcp-recorded-text 10,
stop-with-host-operations 58, failed-create-releases 11,
checkpoint-attribution 10, present-while-acting 57 and
script-structured-references 8.

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 18, 2026
…s failure reaches its listeners, and nothing is written after a pipe fails

A review of the round that answers R2-1 and merges main e670363.

Nothing more goes to a child whose pipe failed:
- StdioTransport.writeLine writes nothing once a pipe has failed. Only the
  request paths checked pipeFailure, so after a stdout-only failure a
  legacy notification or response still reached the child, though the
  getter's doc said no write does. Every write passes writeLine, so the
  rule sits there; the engines' request checks stay, so a request is
  refused as not sent. The getter's doc and both refusal comments now give
  that reason: the transport is ending the child.
- The first pipe error starts the one attempt to end the child, and a
  later one, from either pipe, adds nothing. Each used to attach its own
  catch, so one failed attempt could say 'unreaped' twice.

A close for good that fails:
- A legacy close() that can't reap its child emits no 'close', so no close
  listener takes the server's tools off the list. A disconnect and a
  recycle refresh the list on such a failure themselves. A failed runtime
  connect's close (main's anima-research#459) only logged it, and the initial and
  post-manifest policy refusals' 'close' fallbacks closed inside the policy
  request's try, so a failed close was logged as an unanswered policy, and
  on a manifest change the server's grant and listing stood.
- closeMcplServerForGood closes a legacy connection for good through the
  registry, and when the close fails, refreshes the tool list and rethrows.
  The failed runtime connect's close and both fallbacks use it, the
  fallbacks after the policy try, so a failed close is reported as itself.

A held launch's permanent failure:
- reconnect-failed is control-plane, so it's held until the first ready().
  main's anima-research#459 has ready() and readyControlPlane() do nothing for a
  connection closed for good, which a launch held as unreaped is, so a
  loss held before the first gate released it never reported its
  permanent failure: no mcpl-down alert at startup, and no refresh. Both
  now deliver a closed-for-good connection's own buffered connect-failed
  and reconnect-failed, which need no grant, and nothing else, so anima-research#459's
  rule still holds for what the server sent.

A connect that stop() ends, whose cleanup can't reap:
- Its error offered "disconnect it to retry the reap", which stop()
  refuses once it has begun, and the legacy one left out that the framework
  had stopped. In both engines it now says the framework stopped while it
  was connecting and its cleanup failed, and offers no disconnect.
  McplUnreapedLaunchError keeps its cleanup's failure (cleanup) for that.

Text:
- During a connect, a child whose pipe failed and that outlives SIGKILL is
  held when the connect fails, by the connect's own cleanup, not at once:
  the modern engine has no session to lose yet, and the legacy handshake
  doesn't listen for 'unreaped'. The comments at both wirings and the
  changelog fragment say so.

Tests: the recycle guard's reconnect side (a recycle whose close can't
reap leaves the tools listed for the reconnect loop), a close() on a
failed attempt while the child runs (rejects again, no signal), the
legacy written request's outcome (no-response), close() arriving while the
child runs, and a test name that promised a 2 s it didn't measure.

Red-first, Linux, Node 24.22.0:
- With src at the commit before, 7 new tests fail: in
  mcpl-transport-close, the write after a pipe failure and both early
  holds (ready() and readyControlPlane()); in mcp-server-ownership, both
  engines' stop-ended connects; in mcpl-config-diagnostics, the failed
  fallback close; in mcpl-awareness-barrier, the failed runtime connect's
  close. The recycle guard's new test passes there, since the guard was
  already in the code; its removal below fails it. The tightened
  assertions in older tests pin behaviour that was already right.
- Each of 12 pieces, removed on its own, fails a test: the write gate,
  the first-error rule, the helper's refresh, the runtime connect's close
  through the helper, each fallback's close after the policy try,
  delivering the connection's own reports from ready() and from
  readyControlPlane(), delivering only those, the stop-aware advice, the
  legacy stop text (whose removal also fails the typecheck), and the
  recycle guard's condition.
- With the change, these files pass, each run on its own and unforced:
  mcpl-transport-close 22, mcp-modern-outcomes 40, mcp-server-ownership
  40, mcpl-config-diagnostics 15 and mcpl-awareness-barrier 34 on Node
  24.22.0 and 20.20.2, and mcpl-legacy-lifetime 16,
  mcpl-runtime-lifecycle 37, stop-with-host-operations 58,
  mcpl-manifest-changed 9, failed-create-releases 11,
  mcp-modern-framework 18 and mcp-recorded-text 10 on Node 24.22.0.

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
…t pass, item 8)

Ada's call on the rent pass: the MCPL reconnect fixes leave anima-research#250 for a pull
request of their own on main, since main has the defect too (Esther-2584's
J20464: main refuses a registration sent right after a reconnect's
initialize, -32002), so the fix reaches every host's next release whether or
not anima-research#250 is ready. Crispin-2713 carries it. The line between it and what
anima-research#250 keeps was drawn with him in room-203: the exchange marker goes with the
fixes, since main's own gates open a connection mid-exchange too, and
without it anima-research#250 opens planes mid-exchange only where main can (its two
openers of every connection, startup and resume(), are among main's five).

What anima-research#250 keeps for its gate's removal (item 3):
- readyMcplPlanes as the one opener, with the quiesce check only: no marker
  and no isConnected skip, so it readies a disconnected stub as main's gate
  does, and the stub's buffered connect-failed comes out at startup's open;
- a connect runs its exchange, then opens its own planes; a runtime connect
  or restart whose policy registration throws closes the connection for
  good in the connect's own catch, as main does since anima-research#459;
- the reconnect handler runs its exchange, then opens its connection's
  planes.

Out of anima-research#250, to the reconnect pull request: settlePolicyExchange and
mcplPolicyExchanges, the transport-epoch checks (in the reconnect handler,
the connect and registerMcplServerFeatures), every change to
server-connection.ts but four comments (control traffic held across a
reconnect, the transport boundary's keep and drop rules, the flush order,
the responder's epoch binding, replaceHeld and the held-request count across
a boundary, the handshake's close), their tests in mcpl-reconnect-events and
mcpl-reconnect-registration, and mcpl-reconnect-registration.fixed.md.

- server-connection.ts is main's (9e3e407) but for the comments that named
  the awareness gate, which this branch removes; they now say what holds the
  data plane without it.
- mcpl-reconnect-events.test.ts is main's again.
- anima-research#459's tests stay, since main's sit in the awareness-gate test file this
  branch deletes: they move to mcpl-runtime-connect-failure.test.ts, without
  the check that the marker held the connection at its close. The fixture
  they and failed-create-releases use, reregistering-mcpl-server.mjs, stays
  as it is.
- mcpl-reconnect-reregistration's harness loses the marker and the
  connection's epoch fields.

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
…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
The MCPL reconnect fixes leave anima-research#250 for a pull request of their own on
main, since main has the defect too (main refuses a registration sent right
after a reconnect's initialize, -32002), so the fix reaches every host's
next release whether or not anima-research#250 is ready. The line between that pull
request and what anima-research#250 keeps: the exchange marker goes with the fixes, since main's own gates open a connection mid-exchange too, and
without it anima-research#250 opens planes mid-exchange only where main can (its two
openers of every connection, startup and resume(), are among main's five).

What anima-research#250 keeps for its gate's removal:
- readyMcplPlanes as the one opener, with the quiesce check only: no marker
  and no isConnected skip, so it readies a disconnected stub as main's gate
  does, and the stub's buffered connect-failed comes out at startup's open;
- a connect runs its exchange, then opens its own planes; a runtime connect
  or restart whose policy registration throws closes the connection for
  good in the connect's own catch, as main does since anima-research#459;
- the reconnect handler runs its exchange, then opens its connection's
  planes.

Out of anima-research#250, to the reconnect pull request: settlePolicyExchange and
mcplPolicyExchanges, the transport-epoch checks (in the reconnect handler,
the connect and registerMcplServerFeatures), every change to
server-connection.ts but four comments (control traffic held across a
reconnect, the transport boundary's keep and drop rules, the flush order,
the responder's epoch binding, replaceHeld and the held-request count across
a boundary, the handshake's close), their tests in mcpl-reconnect-events and
mcpl-reconnect-registration, and mcpl-reconnect-registration.fixed.md.

- server-connection.ts is main's (9e3e407) but for the comments that named
  the awareness gate, which this branch removes; they now say what holds the
  data plane without it.
- mcpl-reconnect-events.test.ts is main's again.
- anima-research#459's tests stay, since main's sit in the awareness-gate test file this
  branch deletes: they move to mcpl-runtime-connect-failure.test.ts, without
  the check that the marker held the connection at its close. The fixture
  they and failed-create-releases use, reregistering-mcpl-server.mjs, stays
  as it is.
- mcpl-reconnect-reregistration's harness loses the marker and the
  connection's epoch fields.

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
The MCPL reconnect fixes come out of anima-research#250: main has the defect too (main
refuses a registration sent right after a reconnect's initialize, -32002),
so they are a change to main of their own, anima-research#544.
The line between the fixes and what anima-research#250 keeps: the exchange marker goes
with the fixes, since main's own gates open a connection mid-exchange too,
and without it anima-research#250 opens planes mid-exchange only where main can (its two
openers of every connection, startup and resume(), are among main's five).

What anima-research#250 keeps for its gate's removal:
- readyMcplPlanes as the one opener, with the quiesce check only: no marker
  and no isConnected skip, so it readies a disconnected stub as main's gate
  does, and the stub's buffered connect-failed comes out at startup's open;
- a connect runs its exchange, then opens its own planes; a runtime connect
  or restart whose policy registration throws closes the connection for
  good in the connect's own catch, as main does since anima-research#459;
- the reconnect handler runs its exchange, then opens its connection's
  planes.

Out of anima-research#250, with the fixes: settlePolicyExchange and mcplPolicyExchanges,
the transport-epoch checks (in the reconnect handler, the connect and
registerMcplServerFeatures), every change to server-connection.ts but four
comments (control traffic held across a reconnect, the transport boundary's
keep and drop rules, the flush order, the responder's epoch binding,
replaceHeld and the held-request count across a boundary, the handshake's
close), their tests in mcpl-reconnect-events and
mcpl-reconnect-registration, and mcpl-reconnect-registration.fixed.md.

- server-connection.ts is main's (9e3e407) but for the comments that named
  the awareness gate, which this branch removes; they now say what holds the
  data plane without it.
- mcpl-reconnect-events.test.ts is main's again.
- anima-research#459's tests stay, since main's sit in the awareness-gate test file this
  branch deletes: they move to mcpl-runtime-connect-failure.test.ts, without
  the check that the marker held the connection at its close. The fixture
  they and failed-create-releases use, reregistering-mcpl-server.mjs, stays
  as it is.
- mcpl-reconnect-reregistration's harness loses the marker and the
  connection's epoch fields.

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant