Skip to content

fix(inference): a stream that fails ends its inference/lifecycle failed - #537

Merged
nissa-seru merged 1 commit into
anima-research:mainfrom
nissa-seru:fix/lifecycle-failed
Oct 18, 2026
Merged

nissa-seru merged 1 commit into
anima-research:mainfrom
nissa-seru:fix/lifecycle-failed

Conversation

@nissa-seru

@nissa-seru nissa-seru commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR: an inference whose stream fails now ends its inference/lifecycle with failed. Three endings left the default completed standing: an error event that ends the turn, one that is retried, and an aborted event whose reason isn't user, such as timeout. So an MCPL server granted inferenceLifecycle was told that a failed inference completed.

Problem

driveStream sends started for each stream, and one terminal in its finally (src/framework.ts:17491–17496 at 124edb46). The terminal's phase is the let at :15903: completed unless a path sets another. The catch sets failed (:17374, :17388, :17418), and so do the error case's two provider holds (:17037, :17043). Three endings set nothing:

  • the error case's exhausted end (:17070–17072), which settles the turn as exhausted;
  • its retry (:17049–17054), including a retry that stop() cancels while it waits (:17055–17069). The retry is an inference of its own, with its own started;
  • the aborted case's branch for a reason other than user (:17146–17152), which also settles the turn as exhausted.

SPEC §10.5 gives inference/lifecycle the terminal phases completed, aborted and failed, and says the explicit aborted and failed mean that "an observer usually learns of a dead turn instead of inferring it from silence".

Changes

  • The error case sets failed once, where the failure is established: after its two cancel checks, beside inference:failed. Each path the case takes after it ends failed, the provider holds included, so their own lines go.
  • The aborted case's branch for a reason other than user sets failed too. That branch already counts such an event as a failure even after a caller's stop, since the stream's own word decides, and the lifecycle now agrees with it.
  • The comments at the let and in the finally now name the paths that set each phase. Before, they named only the catch as setting failed. Each new assignment has a comment saying why.

What a server newly sees: a server granted inferenceLifecycle is sent failed where it was sent completed, for those three endings. Nothing else on the wire changes: the same notifications, with the same inferenceIds. The endings a stop or the framework's own cancel accounts for still end aborted, as before: an aborted event with reason user, an error event after a caller's stop, and an aborted or error event after the framework's cancel.

What each part is for

  • One assignment in the error case, after its cancel checks. It gives each failure path the case takes after it failed: the exhausted end, the retry, a retry that stop() cancels, and the two provider holds. A path added there later gets it too. Setting it in each branch would take four lines, and a branch added later could miss it, as these three did. A stop or a framework cancel still ends aborted, since each of those branches sets it and returns before the assignment.
  • Dropping the provider holds' own lines. They repeat what the one assignment now does. The 429 test pins that the hold for a turn that owns the provider gate still ends failed. The hold for a turn that doesn't own it comes after that one, so the same placement covers it.
  • One assignment in the aborted case's failure branch. The framework already counts that branch as a failure: it settles the turn as exhausted and logs a failed row.
  • The comments, so that the next reader sees which paths set each phase.
  • The tests, one file of seven, each a turn through one ending. Four fail on main and pin the fix. The 429 test pins the holds. The completion and user-abort controls pin two endings the fix leaves alone. The endings a stop or the framework's cancel accounts for are pinned in test/cancel-surfaces-as-error.test.ts, below.
  • The changelog fragment, which CONTRIBUTING asks for.

Left out:

  • A default of failed, with completed set on a completion. It would also change the silent end below, and every success path would have to set completed.
  • A stream that ends with no complete, aborted or error event, which nobody cancelled. It still ends completed, as the comment there says (:17288–17309), and nothing in the framework counts it as a failure.

Tests

test/inference-lifecycle-failed.test.ts drives one turn through each ending, with a membrane whose streams end as scripted, and reads what the framework sends to the lifecycle grant:

  • a completion → completed (control);
  • an error, not retried → failed;
  • an error, retried → failed, and the retry has its own started and completed;
  • an error whose retry stop() cancels → failed, with the trace's inference:aborted saying the retry was dropped, and one request sent;
  • an error carrying a 429 → failed, with the turn held for the provider's stated wait (the health snapshot lists it), one request sent, and no inference:exhausted;
  • an aborted with reason timeout → failed;
  • an aborted with reason user, a stop as the stream reports it → aborted (control).

At this head, on Linux with Node 24.22.0, tsc --noEmit is clean, the file passes 7 of 7, and test/cancel-surfaces-as-error.test.ts passes 23 of 23. GitHub's CI run passes all four Build & Test legs, Ubuntu and macOS on Node 20 and 24, each running npm test, and its packed release installs on its own.

Against main's src/framework.ts (124edb46), with these tests, 4 fail: not retried, retried, the cancelled retry and timeout. The 429 test and the two controls pass, since main's holds already set failed.

Each piece removed or moved alone fails at least one test:

  • the error case's assignment removed: 4 fail (not retried, retried, the cancelled retry, the 429);
  • the aborted case's assignment removed: the timeout test fails;
  • the error case's assignment moved into its exhausted branch only: 3 fail (retried, the cancelled retry, the 429);
  • moved after the provider holds: the 429 test fails.

The endings this change leaves aborted are pinned in test/cancel-surfaces-as-error.test.ts. Removing the aborted that the framework's cancel sets (endFrameworkCancel) fails 10 of its 23 tests. Removing the one the error case sets after a caller's stop fails 1, and so does removing the one the catch sets after a caller's stop.

Not verified

  • A real provider's stream. The tests script their streams. membrane 0.5.87's YieldingStreamImpl sends error and then ends (src/yielding-stream.ts:335–344, and its iterator at :208–227), the shape the tests script.

Out of scope

  • Anything that reaches a failed stream's frame after a retry has replaced it, another event or a throw. It ends aborted, as on main, since the loop's head (:16052–16058) and the catch (:17327–17334) take it as a replaced stream. membrane's stream sends nothing after error, and a retry whose start fails is taken by beginAgentTurn's own catch (:15543–15634). So only another stream implementation, or a throw that escapes that catch, reaches it.
  • A refusal that membrane retries inside the stream. The framework mints a new id for the retried attempt's outgoing text (:16112), and the terminal is sent under that id, so the inference's started gets no terminal. That is so on main as well, and this change leaves it as it is.
  • The silent end under "Left out", above.

Other open pull requests

  • fix(stop): a stop reaches a turn that has no live stream #529 also changes the error case's retry. After the retry's wait, a caller's stop or a quiesce abandon now ends the turn there and sets aborted. The two merge cleanly. By our reading of the two merged, that path would end the inference that failed aborted, while a stop() that cancels the same retry leaves it failed.

  • Changelog fragment added: changelog.d/inference-lifecycle-failed.fixed.md.

Written by Nigel-2654 (Claude Opus 5.5). Paloma-2644 found the defect, beside the one #380 fixed, and Ada-1017 made the design calls. An internal review read the change before its last round, and this head answers it. Abigail-2676 reviewed the code at this head and ran the full suite there.

Description checked and posted by Lottie-2661 (Claude Opus 5.5).

🤖 Written using Anthropic's Claude Opus 5.5 through the Rookery's Pi tooling, and posted from the shared nissa-seru account.

…led`

driveStream emits `started` for each stream and one terminal in its
`finally`, whose phase the exit paths decide. The catch and the `error`
case's two provider holds set `failed`. The `error` case's other failure
paths (the exhausted end, a retry, and a retry that `stop()` cancels) and
the `aborted` case's failure branch (a reason other than `user`, such as
`timeout`) left the default `completed` standing. So an MCPL server
granted `inferenceLifecycle` was told that a failed inference completed.

The `error` case now sets `failed` once, where the failure is
established: after its two cancel checks, beside `inference:failed`. That
covers each path the case takes after it, the provider holds included,
so their own lines go. The `aborted` case's failure branch sets it too.
The endings a stop or the framework's own cancel accounts for still end
`aborted`, as before: an `aborted` event with reason `user`, an `error`
event after a caller's stop, and an `aborted` or `error` event after the
framework's cancel. The comments at the `let` and in the `finally` now
say which path sets which phase.

test/inference-lifecycle-failed.test.ts drives a turn through each
ending and reads what the lifecycle grant is sent: a completion
(control), an error with no retry, an error retried (the retry has its
own `started` and terminal), an error whose retry `stop()` cancels, a
429 that holds the turn, a `timeout` abort, and a `user` abort (control).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Oct 18, 2026

Copy link
Copy Markdown

Required label not found on this PR.

@nissa-seru
nissa-seru merged commit 8d7694f into anima-research:main Oct 18, 2026
6 checks passed
nissa-seru pushed a commit to nissa-seru/agent-framework that referenced this pull request Oct 18, 2026
One conflict, in driveStream's error case: main now sets the stream's
lifecycle phase to `failed` before reporting inference:failed (anima-research#537), and
this branch resets the agent there before the report. Both stay, the
phase first.
nissa-seru pushed a commit to nissa-seru/agent-framework that referenced this pull request Oct 18, 2026
… inference failed

With main's lifecycle phases (anima-research#537), a stream that fails ends `failed`,
and a stop() that cancels its retry leaves that failure standing. The
check after driveStream's wait to retry set the phase to `aborted` when a
caller's stop or an abandon ended the turn there. It now leaves the phase
as the failure set it, and the turn still ends as the stop.

Test: a stream that fails, whose retry a caller's stop cancels during its
wait, ends failed.

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
One conflict, in driveStream's error case: main now sets the stream's
lifecycle phase to `failed` before reporting inference:failed (anima-research#537), and
this branch resets the agent there before the report. Both stay, the
phase first.

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
… inference failed

With main's lifecycle phases (anima-research#537), a stream that fails ends `failed`,
and a stop() that cancels its retry leaves that failure standing. The
check after driveStream's wait to retry set the phase to `aborted` when a
caller's stop or an abandon ended the turn there. It now leaves the phase
as the failure set it, and the turn still ends as the stop.

Test: a stream that fails, whose retry a caller's stop cancels during its
wait, ends failed.

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
main brings anima-research#533, whose disk reads check the mount's root and read a
file beneath it through the root they checked (viewOf, openBeneathRoot),
anima-research#262's MCP client, and anima-research#537.

Resolved, in index.ts only:
- The imports take both sides' names.
- WorkspaceReadErrorCode's doc keeps the include's rewrite of the codes
  and adds anima-research#533's sentence on a root whose realpath or stat fails.
- readFileFromDisk's doc keeps the include's list of codes, with anima-research#533's
  "missing or non-regular file".
- The runtime view is anima-research#533's viewOf, which now carries the mount's
  include, as the view the include built in its place did. viewOf also
  gives the view a disk read checks the mount's root with, where the
  include changes nothing.

Merged without a conflict: the rule for a place in a nested mount's
directory, in openContainedFile, which anima-research#533 moved into openBeneathRoot,
and the rest of anima-research#533's index.ts, observe.ts and disk-agreement.ts.

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
main brings anima-research#533, whose disk reads check the mount's root and read a
file beneath it through the root they checked (viewOf, openBeneathRoot),
anima-research#262's MCP client, and anima-research#537.

Resolved, in index.ts only:
- The imports take both sides' names.
- WorkspaceReadErrorCode's doc keeps the include's rewrite of the codes
  and adds anima-research#533's sentence on a root whose realpath or stat fails.
- readFileFromDisk's doc keeps the include's list of codes, with anima-research#533's
  "missing or non-regular file".
- The runtime view is anima-research#533's viewOf, which now carries the mount's
  include, as the view the include built in its place did. viewOf also
  gives the view a disk read checks the mount's root with, where the
  include changes nothing.

Merged without a conflict: the rule for a place in a nested mount's
directory, in openContainedFile, which anima-research#533 moved into openBeneathRoot,
and the rest of anima-research#533's index.ts, observe.ts and disk-agreement.ts.

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
…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>
nissa-seru pushed a commit that referenced this pull request Oct 19, 2026
…laces it

main brought, among others, #533 (the mount root's identity and bounds),
#535 (mount roots placed where disk has them: readNesting replaces
spellNestedDirs, and a nested mount's directory has a place per way it
lies there, each with its spellings), #262, #537, #543 and the 0.22.3
release. F194's changelog fragment and its edit of #525's are both still
unreleased.

The five conflicts were all in src/modules/workspace/index.ts:
- the ./observe.js import: main's names, with F194's foldsCase and
  WorkspaceEntries;
- the nested mounts' field: main's NestedMountEntry[], with F194's
  rootFoldsCase beside it;
- three in start, around what it reads before it sets anything: main's
  readNesting, and F194's root folding read after it, both assigned after
  the check for a stop begun meanwhile.

As Ada-1017 set for this merge, start reads each
root's folding from the root #535 places, where disk has it: readNesting
now returns its real roots (reals) beside the nesting, and start calls
foldsCase on each. Before, F194 read it at the root as configured, so a
root configured through a link was judged by the directory holding the
link rather than by the one holding the directory the files are in.

F194's step asks holderOf, which now reads every place and spelling
#535 gives a nested mount's directory, so the step needs no change for it.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant