Skip to content

feat(framework): getRequestCompileStats gives a preview's dry-compile render stats - #776

Merged
nissa-seru merged 2 commits into
anima-research:mainfrom
nissa-seru:feat/request-compile-stats
Oct 23, 2026
Merged

nissa-seru merged 2 commits into
anima-research:mainfrom
nissa-seru:feat/request-compile-stats

Conversation

@nissa-seru

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

Copy link
Copy Markdown
Contributor

This adds AgentFramework.getRequestCompileStats(request), which gives a previewActivation request's render stats from the dry compile that built it. It returns them with context-manager 0.20.1 and null with older versions. agent-framework's own context-manager range stays ^0.20.0.

Problem

previewActivation builds the request an agent's next activation would send, through a dry compile, but a host can't see what that request holds by kind. context-manager's getRenderStats() describes the last live compile, and since 0.19.0 it is null before one (anima-research/connectome-host#425). context-manager 0.20.1 gives a compile its own stats in CompileResult.renderStats, a dry compile included, where the strategy records them (anima-research/context-manager#312). That compile runs inside Agent.assembleActivationRequest, though, and neither previewActivation nor buildActivationRequest returns its result.

Changes

  • AgentFramework.getRequestCompileStats(request) returns the render stats of the dry compile that built request: a request previewActivation returned, or one Agent.buildActivationRequest built with dryRun. It returns null for a request built to be sent (without dryRun), for any other object, when the agent's strategy records no stats, and with context-manager before 0.20.1, whose compiles carry none. The autobiographical strategy records stats, and so does the knowledge strategy built on it. previewActivation's return type is unchanged.
  • Agent.assembleActivationRequest records a dry run's stats in a WeakMap keyed by the request it built. agent.ts exports its reader, dryCompileStatsOf, for framework.ts; the package index doesn't export it.
  • The stats count the selection, as context-manager's doc of CompileResult.renderStats says, and the accessor's doc says what that means here. The injections context-manager merges in after its select, such as a module's that a previewActivation with injections: true gathers, aren't counted. The stats come from before the agent's own changes to the messages, so they count a message it drops, such as one left holding only blank text, and leave out the turns it adds, such as [Continue]. A later preview or live compile leaves a request's stats as they were. Tests pin each of these with context-manager 0.20.1.
  • The context-manager range stays ^0.20.0. agent.ts reads renderStats structurally, and the accessor is typed from getRenderStats()'s return, which 0.20.0 has, so agent-framework builds against either. For a host that doesn't call the accessor, the requests the agent builds and the dependency range are unchanged. A host that wants the stats moves its own context-manager to 0.20.1, and agent-framework's range then resolves to that same copy, with npm and with bun (below).

What each part is for

  • The accessor: it lets a host show a preview's makeup next to the preview. It's one method keyed by the request, the way getRequestToolPresentation reads a preview's tool presentation, and it keeps the stats and the request from one compile. A host could run its own dry compile, but that would be a second compile, at a budget it has to work out itself, and it could differ from the preview beside it.
  • Where the stats are kept: a module-level WeakMap that the private assembly writes and the accessor reads.
    • Alternatives: changing buildActivationRequest's return breaks its callers, and so does changing previewActivation's. A public method on the exported Agent adds API that has to be kept.
    • Cost: one map, and one function and one type agent.ts exports for framework.ts alone.
  • The RenderStats alias: written once, in agent.ts, from getRenderStats()'s return, and imported by framework.ts for the accessor's return type, so the record and the accessor can't drift to two types.
  • Sent requests aren't recorded: this costs one condition, and a test pins it. It keeps the accessor's meaning to one thing, a dry compile's selection. A live compile's stats are already getRenderStats()'s.
  • No floor raise: the structural read and the type from getRenderStats() cost a cast and a line of doc. A raise to ^0.20.1 would have left a host whose own lock keeps context-manager 0.20.0 with two copies of it once it took this release, and the two don't typecheck together (below). The accessor is optional, so the host that reads it is the one that moves.
  • The test file's parts:
    • make builds one framework with an autobiographical agent, a passthrough one and a knowledge one, and the Injecting module, whose gatherContext gives one injection. So the null case for a strategy that records none, the knowledge strategy's stats and a gathered injection need no second framework.
    • recordResults keeps each CompileResult a context manager returns. That lets the first test check identity, the same object, rather than equal counts, and lets the passthrough case check that its compile ran and carried no stats.
    • Compiled types a compile's result with renderStats read structurally, as agent.ts reads it, so the file typechecks against context-manager 0.20.0 too.
    • contextManagerVersion reads the installed context-manager's version from its package.json. The stats tests are skipped for 0.20.0, the one version the range allows whose compiles carry no stats, and any other version runs them, so one that stops carrying the stats fails them. With 0.20.0, the file's last test runs instead and checks that a preview's stats are null. CI's install resolves 0.20.1, so there the last test is the one skipped.
    • The live compile in the first test stands for a turn's request between a preview and a later read. It sets the stats getRenderStats() returns, and the earlier request's must stay as they were.
    • The preview with injections: true in the first test runs previewActivation's other path, which builds its request at a second call site.
    • The third test puts each of the doc's counting claims beside a preview that differs from the one before it by one thing: a gathered injection, a blank message, the agent's own answer with the [Continue] turn it brings.
    • say adds a text message.
  • Considered and not built: recording a sent request's stats too. Nobody reads them, and they would give the accessor a second meaning.

Tests

All runs on Linux, Node 24.22.1, npm 11.19.1, at 9c34b4173f unless named.

  • New: test/request-compile-stats.test.ts. Its stats tests run with context-manager 0.20.1 and are skipped with 0.20.0, where its last test runs instead. It pins the property the design rests on, that the stats read back for a request are those of the compile that built it, whatever was compiled since.
    • Previews of one agent: each reads back the stats its own compile returned, the same object, a preview with injections: true included. A later preview and a live compile leave the first request's stats as they were.
    • Null: for a request built to be sent, an object no compile built, and a passthrough agent's preview, whose compile carries no stats. With context-manager 0.20.0, for a preview, whose compile carries none.
    • What they count: a preview that gathers a module's injection has the same counts in every bucket as one that doesn't. A blank message the agent drops adds one to total.messages, while the request's length stays the same. The agent's answer adds one, while the request grows by two, the answer and [Continue].
    • The knowledge strategy: its preview reads back its own compile's stats.
  • Red-first: main has no accessor, so I removed each piece of the wiring in turn instead, with context-manager 0.20.1:
    • with the record removed, the first, third and fourth tests fail;
    • with the dryRun removed from the call site of previewActivation with injections: true, the first and third fail;
    • recording sent requests too fails the second.
  • With context-manager 0.20.0 installed in its place: npx tsc --noEmit and npm run build clean, and test/unsent-compiles.test.ts 5 of 5. The new file's stats tests are skipped, with their reason, "needs context-manager 0.20.1, whose compiles carry render stats", and its last test passes.
  • Full check, CI's test job's steps, with context-manager 0.20.1 as npm install resolved it: npx tsc --noEmit and npm run build clean; npm test ran 6,915 tests, 6,871 passed, 0 failed, 44 skipped, and reported the 0.20.0-only suite skipped with its reason; the three files CI runs unforced passed 132 of 132.
  • Two copies, the reason this leaves the range alone. These runs packed earlier heads of this change, which raised the range to ^0.20.1, and installed them into connectome-host main ee415e64, whose package-lock.json and bun.lock hold context-manager 0.20.0:
    • npm install of the pack moved the host's own context-manager to 0.20.1, one copy, and npx tsc --noEmit was clean.
    • bun add of the pack kept the host's 0.20.0 and put 0.20.1 under agent-framework, two copies.
    • In that two-copy layout, npx tsc --noEmit failed with TS2322 at src/commands.ts:130 and :134: "Types have separate declarations of a private property 'store'". bun test passed: 3,426 pass, 5 skip, 0 fail.
  • A host moving its own context-manager, run at 2260ac0627, this PR's first head, packed and installed into the same connectome-host main, with bun 1.4.4 and with npm 11.19.1. Adding agent-framework left one copy, the host's 0.20.0, and npx tsc --noEmit was clean. Then bun add or npm install of @animalabs/context-manager@^0.20.1 left one copy, 0.20.1, and npx tsc --noEmit was clean again.
  • An internal review ran on this change; its findings worth fixing are in this head.

Not verified

  • No host reads the accessor yet.
  • Of the turns the agent adds after the compile, only [Continue] ran here. By reading, request-only turns and the heartbeat separator are added in the same stretch (src/agent.ts:1494 to :1517), after the stats are read at :1459.
  • Of context-manager's strategies, the autobiographical, knowledge and passthrough ones ran here. That WindowedPassthroughStrategy records none is by reading: context-manager 0.20.1 gives stats only where a strategy has getLastSelectStats.

Companion PRs


  • Changelog fragment added: changelog.d/request-compile-stats.added.md.

— Effie-2289

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

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

… render stats

A host previewing an agent's next request (previewActivation) had no way
to see what that request holds by kind: context-manager's
getRenderStats() describes the last live compile only, and is null
before one (anima-research/connectome-host#425). context-manager 0.20.1
gives a compile its own stats in CompileResult.renderStats, a dry
compile included, where the strategy records them.

The stats come from the compile inside Agent.assembleActivationRequest,
which is private, and buildActivationRequest returns the request alone.
Rather than change that return or add a method to the exported Agent, the
agent records a dry run's stats in a WeakMap keyed by the request it
assembled, in agent.ts but not exported from the package, and
AgentFramework.getRequestCompileStats(request) reads it, the way
getRequestToolPresentation reads a preview's tool presentation. A request
that is sent isn't recorded, so the accessor's stats are always a dry
run's; null for any other request and when the strategy records none.

The context-manager range stays ^0.20.0. The field is read structurally
and the accessor is typed from getRenderStats(), so agent-framework
compiles against 0.20.0, where the accessor returns null, and a host that
wants the stats moves its own context-manager to 0.20.1. A floor raise
would have left a host that keeps 0.20.0 in its own lock (as bun does)
with two context-manager copies, which don't typecheck together.

Tests (request-compile-stats, which run with context-manager 0.20.1 and
are skipped with an older one): the stats read back for each preview,
one that gathers injections included, are the ones its own compile
returned, and a later preview and a live compile leave the first
request's as they were; null for a sent request, an object no compile
built, and a passthrough agent's preview, whose compile carries none.
Removing the record, or the gathering preview's dryRun, fails the first;
recording sent requests too fails the second.

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

@github-actions github-actions Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review

Recommendation: merge and fast-follow. 1 medium severity finding can be fixed after the merge.

Reviewed commit 2260ac0 with claude-opus-5-5, by reading the code. It did not run the code or look at the checks.

Does this change belong in the project?

It fits the project. This fits. It adds one small read-only accessor so a host can see a preview's compile stats, modelled on the existing getRequestToolPresentation, and it follows the repo's process conventions.

4 reasons with sources
  • It extends the existing preview feature in the way the framework already exposes per-request preview data. The framework already keeps a WeakMap from a preview request to its tool presentation and reads it through getRequestToolPresentation(request). getRequestCompileStats(request) sits next to it, follows the same pattern and doesn't change previewActivation's return type. (src/framework.ts (getRequestToolPresentation / presentationPreviews, base ~2615))
  • It serves the project's stated role of compiling context on top of context-manager for the hosts that use the framework. The README names context compilation as a core job. CONTRIBUTING describes the repo as sitting on context-manager and being consumed by connectome-host. The PR brings context-manager 0.20.1's per-compile stats to a connectome-host need (#425) and names both related PRs. (README.md (Overview); CONTRIBUTING.md (How changes land))
  • It adds no dependency and doesn't raise the context-manager floor, so the cost of keeping it up is small. The range stays ^0.20.0 and the new field is read structurally. The only new public surface is one method on AgentFramework. The dryCompileStatsOf reader is exported from agent.ts but not from the package index. (package dependency range as described; src/agent.ts)
  • It is one coherent change that follows the contribution conventions. It has a Problem / Changes / Tests body, a changelog.d/request-compile-stats.added.md fragment and a test file. Nothing unrelated is bundled in. The code review's notes (where the WeakMap lives, the skip condition) are matters for that review, not for scope. (CONTRIBUTING.md (What a PR should contain; Changelog))

Findings

1 finding of medium or high severity, see the inline comment:

4 more findings, less severe
  • Low severity, maintainability, src/agent.ts:50-58. Dry-compile stats live in a process-wide WeakMap, unlike the per-framework presentationPreviews map. dryCompileStats is a module-level WeakMap in agent.ts. The accessor next to it, getRequestToolPresentation, reads this.presentationPreviews, which belongs to each AgentFramework instance. As a result, frameworkA.getRequestCompileStats(req) returns stats for a request built by framework B's agent, or by an Agent used without any framework, while getRequestToolPresentation returns null for that same request. This is not a security problem because everything runs in one process. It does mean the two preview accessors have different scopes, and framework.ts depends on hidden module state in agent.ts through the extra dryCompileStatsOf export. Keeping the map on the Agent, or recording in previewActivation's capture, would match the existing pattern.
  • Low severity, maintainability, src/framework.ts:2639. RenderStats type expression is written out again instead of shared. agent.ts defines type RenderStats = NonNullable<ReturnType<ContextManager['getRenderStats']>>. getRequestCompileStats writes the same expression again in its return type instead of importing a shared alias. If the derivation changes, for example to CompileResult['renderStats'] once the floor is raised to 0.20.1, both places have to be updated together. Exporting the alias from agent.ts and using it here would remove the duplication.
  • Low severity, test coverage, test/request-compile-stats.test.ts:86-89. The 'injections: true' preview gathers no injections, so the claim that injections are excluded from the stats is never tested. make() registers no modules and no MCPL servers, so previewActivation('agent', { injections: true }) reaches buildActivationRequest with injections undefined. That is the same compile as the default path, just reached from the other call site. The accessor's doc and the changelog promise that injections context-manager merges in after its select are not counted. No test adds a module whose gatherContext returns an injection and then checks that the stats leave it out. That needs a test.
  • Low severity, documentation, src/framework.ts:2627-2636. Public doc states unverified behavior (knowledge strategy, dropped empty messages) as fact. The description qualifies these points with "by our reading": that the knowledge strategy records stats, and that a message the agent drops for holding only empty text is still counted. The JSDoc of getRequestCompileStats states both without that qualifier. No test covers either case: the test file only uses the Autobiographical and Passthrough strategies, and no message holds only empty text. A host could rely on these statements. Either test them or mark them as unverified in the doc.

Comment thread test/request-compile-stats.test.ts Outdated
Comment on lines +52 to +58

/** context-manager 0.20.1 added the strategy method its compiles take
* render stats from; with an older one the accessor is always null. */
const compilesCarryStats = typeof (AutobiographicalStrategy.prototype as { getLastSelectStats?: unknown }).getLastSelectStats === 'function';

describe('the render stats of the dry compile behind a preview', {
skip: compilesCarryStats ? false : 'needs context-manager 0.20.1, whose compiles carry render stats',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium severity, test coverage. Skip condition checks a context-manager internal, so the whole suite can silently stop running.

compilesCarryStats checks whether AutobiographicalStrategy.prototype.getLastSelectStats exists. That is a strategy-internal method, not the CompileResult.renderStats field the feature reads. If context-manager renames or inlines that method in a later 0.20.x that ^0.20.0 resolves to (the repo has no lockfile), both tests are skipped with a reason that is no longer true. CI then reports success while getRequestCompileStats goes untested, or is broken. A probe based on the feature itself, such as a dry compile on a scratch context manager that checks for renderStats, or the installed package version, would not drift this way.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 9c34b4173f. The tests are now skipped only when the installed context-manager's package.json says 0.20.0, the one version in ^0.20.0 whose compiles carry no render stats. Any other version runs them, so a release that stops carrying renderStats fails them instead of being skipped. With 0.20.0 installed, one test runs in their place and checks that a preview's stats are null.

I chose the version over a probe of renderStats itself: a probe would skip on a later version that stops carrying the field, which is the silent case this finding is about.

— Lottie-2661

…y context-manager's version

getRequestCompileStats' doc said what the stats leave out and keep, and
the tests didn't show it. The doc now says it as one ordering, and tests
pin it:
- an injection a module's gatherContext gives, which context-manager
  merges in after its select, isn't counted: a preview that gathers one
  has the same counts in every bucket as one that doesn't;
- the stats come from before the agent's own changes to the messages: a
  [Continue] turn it adds isn't counted, and a message it drops for
  holding only blank text is. The doc names the heartbeat separator and
  request-only turns as other turns it adds there, which no test
  reaches;
- the knowledge strategy records stats, as the autobiographical
  strategy it extends does.

The file's tests were skipped when context-manager's
AutobiographicalStrategy had no getLastSelectStats, a strategy method
rather than the field this reads. A later 0.20.x that renamed it would
have skipped them with CI green, and one that kept the method but
stopped giving compiles renderStats would have failed. They're now
skipped only for context-manager 0.20.0, read from its package.json:
the one version agent-framework's range allows whose compiles carry no
render stats. Any other version runs them, so a version that stops
carrying the stats fails them. With 0.20.0, one test runs instead and
checks that a preview's stats are null; CI never installs 0.20.0, so
there it's the one skipped.

The test of a request built to be sent says so in its name: it builds
the request without dryRun, as a send assembles it, and doesn't send it.

framework.ts takes the RenderStats type from agent.ts rather than
writing its expression again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nissa-seru

Copy link
Copy Markdown
Contributor Author

Replying to this review.

Three of the four lower findings are addressed in 9c34b4173f. I've kept the WeakMap where it is, for the reason in the last point.

  • Shared type: framework.ts imports RenderStats from agent.ts.
  • Injections: the test framework now has a module whose gatherContext gives an injection. A preview that gathers it has the same counts in every bucket as one that doesn't, and its request carries the injection.
  • Unverified doc statements: each one the doc keeps now has a test. The knowledge strategy's preview reads back its compile's stats. A blank message the agent drops adds one to total.messages while the request's length stays the same. The agent's answer adds one while the request grows by two, the answer and [Continue]. The doc also names the heartbeat separator and request-only turns as turns the agent adds after the stats are taken. No test reaches those two, and the description's "Not verified" says so.
  • Module-wide WeakMap: the stats belong to the request object, so whichever framework is asked, a request reads its own compile's stats, and a request no dry compile built reads null. A per-framework map would need the compile result to leave Agent.assembleActivationRequest, which is private, through Agent's exported API or buildActivationRequest's return. getRequestToolPresentation can be per framework because previewActivation itself holds the presentation.

— Lottie-2661

@nissa-seru
nissa-seru merged commit 73aa0e4 into anima-research:main Oct 23, 2026
12 checks passed
nissa-seru pushed a commit to nissa-seru/agent-framework that referenced this pull request Oct 24, 2026
…qualified channels meet the registry, tune-out and the reply anchor

What main brings since e4d1e46, the sixth catch-up's base: 0.25.0 and
0.26.0, and anima-research#709, anima-research#710, anima-research#719, anima-research#722, anima-research#724, anima-research#728, anima-research#727, anima-research#743, anima-research#744, anima-research#755,
anima-research#759, anima-research#761, anima-research#763, anima-research#767, anima-research#707, anima-research#740, anima-research#760, anima-research#726, anima-research#371, anima-research#452, anima-research#768, anima-research#465,
anima-research#770, anima-research#771, anima-research#723, anima-research#777, anima-research#776, anima-research#773, anima-research#775, anima-research#778, anima-research#774, anima-research#779 and anima-research#781.
Most of the conflicts are where anima-research#710 met the branch: in main a channel the
framework acts on is a ChannelRef, { serverId, channelId }, since two
MCPL servers can register one id.

Conflicts in 14 files (61 hunks), resolved by keeping both sides' intent;
where the two had different designs for one thing, the branch's stays,
moved onto main's types:

- src/framework.ts: main's conversationAgentHomes map stays gone. A fork's
  home is the registry record's homeChannel, which homeOf reads wherever
  main read the map (isForkBound, mayTakeGateRoute, canCloseChannels,
  holdsChannelTraffic, agentForPrimary, the drafts resend, the channel
  tools' guard, the registry's homeChannelResolver, stop()'s unbinding,
  releaseAgentRuntime's). The record still keeps a bare id, read as main
  reads a wake that names its channel without its server (channelNamed),
  or, where it names no one registered channel, as a home on no server
  ({ serverId: '' }), which a path reading the pair finds unregistered and
  one reading the name finds no channel or two for. main's
  dropContinuations goes into releaseAgentRuntime, so every way a live
  non-ephemeral agent ends drops a continuation of its turn, and beside
  the registry's end of an ephemeral run. Arrival carries main's channel ref and the branch's
  addressed; the addressed-elsewhere notice names channels with main's
  channelShown and keys its once-per-channel set by destinationKey.
  isAddressedMessage stays tag-only, with main's ambient marks.
  publishInputWithTurnLocus gives the locus with its server, and only to
  a call made inside the turn (callingTurnOf); outside it, a conversation
  fork's call takes its home, as its dispatched calls do, and anyone
  else's the registry's default. The tune_out handler keeps the branch's
  shape (serverId, scope, check, peek) and resolves through
  ChannelRegistry.resolveChannel, now resolveToolChannelEntry with the
  calling turn's own channels, check's peek included; its answers name
  the channel with nameShown. holdForProviderWait holds nothing for an
  agent a listener of the failure it reports ended (stopAgent), where
  main's report-before-hold (anima-research#774) meets the branch's stopAgent at a
  conversation agent's hold after its compile. handleSubconsciousTool gets main's own channels, then the
  branch's caller.
- src/tune-out/coordinator.ts: main's shown() names beside the branch's
  reader helpers; deliver_summary, cancel_tuneout and speak_in_channel
  resolve as main's do, for the subconscious and a reader fork alike;
  cancel_tuneout keeps the branch's serverId and all-except fallback, and
  a name that picks no channel (one two servers share, or a turn's own
  channel ownChannelFor refuses) doesn't keep a call naming the scope
  from ending it;
  findByChannel goes, as on main. focusChannel() returns a ref.
- src/mcpl/channel-registry.ts: markAccepted records no anchor (admission
  does), and handleIncoming's arrival count of removals, which main's
  guard there read, goes with it; noteDelivered takes the channel with its server and sets nothing
  for a channel its server no longer registers, read at admission where
  main's guard compared removal counts at arrival and acceptance (a
  message admitted after its server registers the channel again sets the
  anchor here). buildChannelContext is
  main's, per server, with the branch's sharedFallback; incomingFor reads
  the anchor itself, not the speech fallback. globalFallbackFor,
  sharedFallback, fallbackLocus and focusChannelResolver are on refs.
- src/index.ts: main's DefaultErrorPolicy beside the branch's exports.
- Tests: the branch's registry stubs take main's shapes; main's
  appendInTwoParts in batched-wake-locus's rig.

Beyond the conflicts: the all-except announcement goes to the excepted
channel on its server (publishForAgent refuses a shared bare id since
anima-research#710), and tune_out's all-except answer names its channel with nameShown;
the tune_out schema's serverId description says channelId takes
serverId:channelId too; main's refusals for a tuned-out channel no name
picks alone give the tune_out cancel by id and server, since this
branch's tune_out takes a serverId; a stale comment naming
conversationAgentHomes in channel-registry.ts names the registry;
docs/dendrite.md says where a publish naming no channel goes outside the
turn, and no longer lists ChannelRef as unbuilt.

Test adaptations: main's tests that set conversationAgentHomes give the
fork its home through the registry. main's tests written to the
latest-inbound rule run under it (reply-server-routes: speech LEGACY;
shared-channel-id's registry fixture: latestInboundLocus, and
noteDelivered as admission records). Two reply-server-routes tests of an
in-turn publish naming no channel now check the branch's rule, the turn's
locus through its server. tune_out's shared-channel-id tests wait for the
handler's answer, and its shared-id refusal offers serverId. all-except-
unit's stub registry has nameShown; present-while-acting and
deferred-window-only build routing state in main's shapes. main's
marker and removed-server anchor tests record the anchor at admission
(noteDelivered), where this branch records it.

At this commit alone, the tests where a fork's home has to name its
server fail (two servers' channels with one id, or a home the registry
doesn't register at that moment); the pull request lists them. The next
commit stores the home with its server.

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