Repository navigation
fix(server): linked launches inherit the caller's mode, capped by the link - #5
Conversation
… link A thread launched over an environment link without a runtimeMode started at the receiving project's default for new threads. The fork's default is approval-required (upstream: full-access), so a full-access caller's task silently dropped to approval-required on the other side. The tool description and orchestrator-mcp-server docs promise inheritance, and two upstream tests (PeerForwarding, RemoteDelegation) pin it. t3_thread_launch now starts a linked session's launch at the forwarded ceiling: the remote caller's modes capped by the link's access. Local MCP clients outside a thread still start at the project default within their ceiling. This reverts 7f47d29, which had changed the two tests to expect the project default instead. Fails before: PeerForwarding "launches in a linked environment with the caller's modes" received approval-required, expected full-access; RemoteDelegation "a task named only by environment inherits the parent's model, within the link" received approval-required, expected auto-accept-edits. After: those plus project handlers.test and linkOrigin.test pass, 42/42. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
|
CI on eee5e3b (run 41411301715): Check is red because of four jobs that also fail on this PR's base. #4's own run at 4150b20 (41395174419) fails the same four. None of the failing files is in this diff; it changes only
What this PR targets now passes in CI. The two tests it changes both run in shards above, before those shards stop at their unrelated failures:
At 4150b20, Test Server 2 and 3 failed on exactly these two tests. Lint, Build and Typecheck, and Test Server 1, 4, 5, 6 and 8 are green. Fix. All four are being fixed on #4's branch, Generated by Claude Code |
eee5e3b started any linked launch that omitted runtimeMode at the forwarded T3-Mode-Limit. For a calling thread that limit is its own running mode, which is what should carry over. For an MCP client outside a thread it is only an approval ceiling, so a full-access client launching through a full-access link got a full-access thread there. The same client launching locally gets the project default. The forwarder now marks the limit as inheritable with T3-Mode-Inherit: 1, and only when the caller is a thread. The receiving /mcp records that beside narrowedTo. t3_thread_launch skips the project default only for a caller that sent it. A client outside a thread starts at the far side's project default, within its ceiling and the link, as it does here. Mixed versions keep today's default: an old receiver ignores the header, and an old sender never sends it. docs/internals/remote.md states the rule. Fails before: the new client case in PeerForwarding "launches in a linked environment with the caller's modes" received full-access, expected approval-required. After: PeerForwarding, RemoteDelegation, project handlers, linkOrigin and McpHttpServer tests 66/66; tsc, fmt and lint clean on the changed files. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br
The independent re-reviews of b73f8fe found three gaps. - The receiving /mcp accepted T3-Mode-Inherit from any OAuth client, so a non-link client could start its own omitted-mode launch at its ceiling rather than the project default. That widens no access, but it breaks the rule that a client outside a thread keeps the local default. - No test pinned that an inheriting launch takes the caller's own mode rather than the link's access. - No test pinned the receiver's header rules. Changes: - withModeLimit sets inheritsModes only for a linked client. - PeerForwarding's launch test adds a thread whose mode (auto) sits between the box default and the full-access link. It must start at auto. - McpHttpServer's T3-Mode-Limit test gains a peer-link caller and pins four rules: inherit is honoured beside a valid limit; ignored without one; ignored unless the value is "1"; ignored from a non-link client. - The MODE_LIMIT_HEADER doc now says a broad limit gains no access, rather than nothing. - docs/internals/remote.md states the receiver rule and mixed-version behaviour. - docs/user/remote-access.md tells users what mode a linked task starts in. Fails before: with the linked check removed (b73f8fe's receiver), the McpHttpServer T3-Mode-Limit test fails on the non-link row. After: PeerForwarding 6/6 and the McpHttpServer T3-Mode-Limit test pass. tsc, fmt and lint are clean on the changed files. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br
The re-review of 2799d3c approved it and noted three wording problems in its text: - The user doc said a linked launch that inherits nothing starts at "that machine's default". The code applies the project's effective default (resolveProjectSettings), so it now says "that project's default there". - "behaviour" and "honour(ed)" are now US spelling, to match the rest of the docs. - withModeLimit's comment now says the function also applies a peer link's T3-Mode-Inherit. Comments and docs only; fmt and lint clean. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br
Brings in #4's remaining test fixes (f0924f6), so this PR's CI runs against a green base. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This PR includes: - #3: GitHub-hosted runners; - the round-1 and round-2 test-suite fixes, 12 groups; - #5: linked launches inherit the caller's mode, capped by the link. CI is fully green at 05b04f7. Round 2 was verified with PASS, with mutation checks on every fix group. The Codex code and security reviews found nothing. No assertion was removed, skipped or loosened. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br
Brings in the fork's CI runner and test-suite fixes (#3, #4, #5) so this PR's CI runs on GitHub-hosted runners against a green base. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br
main now carries #3, #4 and #5, which add GitHub-hosted CI and the fork's test-suite fixes. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br
Brings in the fork's CI runner and test-suite fixes (#3, #4, #5) so this PR's CI runs on GitHub-hosted runners against a green base. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br
main now carries #3, #4 and #5, which add GitHub-hosted CI and the fork's test-suite fixes. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br
Problem
t3_thread_launchcan be called over an environment link. When the call leaves outruntimeMode, the new thread started at the receiving project's default mode. In this fork that default isapproval-required(upstream:full-access). So a full-access agent's linked task silently dropped toapproval-requiredand waited for approvals on the other machine.That contradicts the tool description ("Omit … modes to inherit yours") and
docs/orchestration-v2/orchestrator-mcp-server.md. It also contradicts two upstream tests that fail on this fork's CI (run 41388349181, Test Server 2 and 3):PeerForwarding.test.ts› "launches in a linked environment with the caller's modes, retry-safe";RemoteDelegation.test.ts› "a task named only by environment inherits the parent's model, within the link".#4 had changed those tests to expect the project default (7f47d29). That runs against the owner's intent, so this PR reverts it.
Change
The rule now:
How:
PeerForwardingmarks the forwarded limitsinherit: trueonly for a calling thread.PeerMcpClientthen sendsT3-Mode-Inherit: 1besideT3-Mode-Limit.McpHttpServer.withModeLimitsetsclient.inheritsModesonly when three things hold: the caller is a peer link, the header is exactly1, and a validT3-Mode-Limitis present. It reads the header per request.t3_thread_launchskips the project default only for that caller.docs/internals/remote.mdstates the rule.docs/user/remote-access.mdtells users which mode a linked task starts in.Commits:
linkOriginwithModeLimitcommentScope and approval
Wes chose "Inherit, capped by link" on November 2, 2026. The question was what mode a linked or delegated task starts in when none is named. He also gave autonomy to drive the fork's CI green.
The client-outside-a-thread case follows from that rule: such a client has no mode to inherit, so it keeps the local rule. It is the narrower default.
This PR is stacked on #4 and changes only this one rule.
Verification
Fail-before:
approval-required.full-accesswhereapproval-requiredwas expected.+inherit.Pass-after (2799d3c):
PeerForwarding.test.ts,RemoteDelegation.test.ts,project/handlers.test.ts,linkOrigin.test.tsandMcpHttpServer.test.ts.tsc --noEmit -p apps/server,vp fmt --checkandvp lintare clean.Mutation proofs (independent reviewer, disposable worktree):
McpHttpServerT3-Mode-Limit test fails.PeerForwardingfails on theautorow.PeerForwardingfails on the client row.CI at 2799d3c:
PeerForwarding6/6,RemoteDelegation26/26 andMcpHttpServer24/24.Review:
Not checked: a live two-environment link session; T3 Connect or relay handling of the new header.
Merge danger
runtimeModenow runs at the agent's own mode, up to the link's access, not at the receiving environment's default. A full-access agent on a full-access link starts full-access work there by default.T3-Mode-Inherit. It is backward-compatible both ways, and honoured only from peer links. It only chooses a default within limits the caller already has.delegate_taskdoes not step an inherited mode down to the far provider's supported modes, unlike a local one. At thread start, an unsupported mode falls back toapproval-required(RuntimePolicy.providerRuntimeMode), so the result is narrower, never broader.fix/fork-test-suite(fix: make the SynthOS fork's CI run and pass #4) after fix: make the SynthOS fork's CI run and pass #4's remaining fixes land.🤖 Generated with Claude Code
https://claude.ai/code/session_01A1D6J2UMPo7YBWQFvbg1br