From 41d47041382f0cb5668bde8e168f34f8aee21adf Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sun, 14 Jun 2026 21:48:31 -0700 Subject: [PATCH] FN-6465: document ACP Route A recovery blockers Record the unrecovered Route A U9 verdict and the design-only U14 confirmation so follow-up work preserves the ACP permission-gate blocker.\n\n- Add an ACP contract open-question entry that marks Route A as NOT GO until real MCP forwarding and ACP permission-gate traversal are proven.\n- Capture the FN-6465 recovery outcome in the Claude ACP runtime plan, including the missing FN-6459 evidence and required rerun criteria.\n- Confirm the internal Route A design mechanisms while keeping implementation blocked on U9.\n\nFiles changed:\n docs/acp-contract.md | 24 ++++++++++++++++++++++\n .../2026-06-14-001-feat-claude-acp-runtime-plan.md | 9 ++++++++\n 2 files changed, 33 insertions(+) Fusion-Task-Id: FN-6465 Fusion-Task-Lineage: d4762440-cbb9-4206-b4b2-be578eba30dd --- docs/acp-contract.md | 24 +++++++++++++++++++ ...-06-14-001-feat-claude-acp-runtime-plan.md | 9 +++++++ 2 files changed, 33 insertions(+) diff --git a/docs/acp-contract.md b/docs/acp-contract.md index cd2a7f7b88..a157a9c25a 100644 --- a/docs/acp-contract.md +++ b/docs/acp-contract.md @@ -100,3 +100,27 @@ enabled (writes default OFF). - `@agentclientprotocol/sdk` v0.24.0 — https://www.npmjs.com/package/@agentclientprotocol/sdk - Validation: the SDK example echo agent (CI) + an in-repo controllable fixture (`src/__tests__/fixtures/echo-agent.mjs`); Gemini CLI / Claude-adapter for manual e2e. + +## Open Questions + + + +### OQ1 — Route A MCP-over-ACP forwarding and permission-gate traversal + +**Status:** UNRESOLVED / BLOCKED as of FN-6465 (2026-06-14). **Combined Route A verdict: NOT GO** until this OQ records both required U9 answers as GO. + +**Recovery status:** NOT-RECOVERED. `fn_task_show FN-6459` retained only archived task metadata plus an archive log entry, `.fusion/tasks/FN-6459/` is absent in the FN-6465 worktree, and `fn_task_document_read(key="research")` returned not found from FN-6465's execution context. No surviving authoritative FN-6459 U9 verdict was available to transcribe. + +**U9 answers required before Route A implementation:** + +1. Whether `claude-code-cli-acp` can forward the real Fusion MCP server(s) supplied through ACP `session/new.mcpServers` to the underlying interactive `claude`, using the actual `packages/pi-claude-cli/src/mcp-config.ts` stdio shape (`{ command: "node", args: [serverPath, schemaFilePath] }`), not a stub. +2. Whether a forwarded Fusion tool invocation surfaces back to Fusion as ACP `session/request_permission` and therefore traverses the existing permission gate, or whether the bridge lets `claude` invoke the MCP tool autonomously inside the bridge, bypassing the gate. + +**FN-6465 result:** these answers remain unproven. Local binaries were present during recovery (`claude` 2.1.177 and pinned `claude-code-cli-acp` 0.1.1), but FN-6465 did not complete an authenticated, instrumented spike against the real Fusion MCP config with ACP permission telemetry. Do not infer a GO from binary presence. + +**Escalation path:** rerun U9 with an authenticated `claude`, the pinned bridge, a non-empty `session/new.mcpServers` generated from the real Fusion MCP config builder, and explicit instrumentation for `session/request_permission`. If MCP servers are ignored, forwarded tool calls cannot be invoked, or tool calls bypass the ACP permission gate without an MCP-layer permission hook or sensitive-tool exclusion, Route A remains blocked and the missing capability must be sponsored upstream in the bridge and/or ACP forwarding layer. A `claude -p` fallback is not an acceptable Route-A completion path. + +**U14 internal mechanisms:** GO for design, subject to U9. Route A should use a second `acp-claude` runtime posture rather than mutating the generic `acp` runtime; inject the ACP bridge client from the engine `registerExtensionProviders` seam into the vendored `@fusion/pi-claude-cli` provider options; and add `AgentRuntimeOptions.mcpServers` to both the engine runtime contract and the ACP plugin-local structural copy, with `newAcpSession` defaulting to `[]` for Route-B compatibility. diff --git a/docs/plans/2026-06-14-001-feat-claude-acp-runtime-plan.md b/docs/plans/2026-06-14-001-feat-claude-acp-runtime-plan.md index de04b695ca..4dce0de6c7 100644 --- a/docs/plans/2026-06-14-001-feat-claude-acp-runtime-plan.md +++ b/docs/plans/2026-06-14-001-feat-claude-acp-runtime-plan.md @@ -136,6 +136,7 @@ sequenceDiagram ## Open Questions - **OQ1 (blocking for Route A; resolved by U9) — Can Fusion's MCP tools traverse the ACP bridge to Claude, *through the permission gate*?** Two parts: (a) does `claude-code-cli-acp` plumb `session/new` `mcpServers` to the underlying `claude` (its README does not mention MCP); and (b) **do the resulting tool calls surface as ACP `session/request_permission` (gated), or does `claude` invoke them autonomously inside the bridge, bypassing the gate?** U9 must test **(b) with the real Fusion MCP config** that `mcp-config.ts` builds — not a trivial stub — and record both answers. If tool calls bypass the gate, a separate control (MCP-layer hooks, or excluding sensitive-category tools from forwarding) is required before U10. Mandatory-`-p` means a no-go escalates to upstream work, not a `-p` fallback. + - **FN-6465 recovery outcome (2026-06-14): UNRESOLVED / BLOCKED; combined Route A verdict: NOT GO.** Recovery status: **NOT-RECOVERED** — `fn_task_show FN-6459` retained only archived task metadata plus an archive log entry, this worktree has no `.fusion/tasks/FN-6459/`, and `fn_task_document_read(key="research")` returned not found in FN-6465's context. No authoritative U9 verdict survived to transcribe. The U9 spike was **not re-run to a verdict** in this recovery task: local binaries are present (`claude` 2.1.177 and pinned `claude-code-cli-acp` 0.1.1), but no authenticated, instrumented run against the real Fusion MCP config and ACP `session/request_permission` telemetry was completed. Therefore both security-critical U9 answers remain unknown: (1) forwarded real Fusion MCP tool invocation through the bridge is **unproven**; (2) permission-gate traversal versus bridge-local autonomous invocation is **unproven**. FN-6460 must not start U10-U13 until a follow-up spike records both answers here and in `docs/acp-contract.md`; the no-go path is upstream bridge/ACP MCP passthrough or permission-hook work, not a `claude -p` fallback. - **OQ2 (blocking sub-gate of U11) — Resume loss is amnesia, not a slowdown.** On resume the provider sends **only the latest user turn** (`buildResumePrompt`, `packages/pi-claude-cli/src/provider.ts:114-125`) and relies on `--resume` to load prior conversation from disk. The ACP path opens a **fresh session per turn** with no `sessionId` passthrough (`loadAcpSession` deferred). Dropping resume **without** switching to full-history prompts makes Claude answer multi-turn chat/executor conversations with zero prior context — silently. **Decision required in U11:** either thread `sessionId` → `loadAcpSession`, or send full flattened history (`buildPrompt`) every turn. No path may send latest-turn-only without resume. - **OQ3 (blocking sub-gate of U11) — Tool-call & partial-message fidelity through the round-trip.** The provider consumes native `stream-json` with `--include-partial-messages` (exact tool-call argument boundaries); the ACP path re-derives chunks from transcript-JSONL → ACP `session/update` → the event bridge, which sanitizes/space-repairs/bounds the stream. Confirm tool-call arguments survive with intact start/end correlation and no space-repair corruption of JSON args, and that executor/reviewer lanes tolerate the transformed deltas. Capture exact tool-call argument bytes in U11's characterization tests, not just token ordering. @@ -301,6 +302,8 @@ plugins/fusion-plugin-acp-runtime/src/ **Approach:** Drive the bridge over ACP with a non-empty `session/new` `mcpServers` carrying **the real Fusion MCP config that `mcp-config.ts` builds today** (not a trivial stub — size, server count, and stdio transport assumptions must be exercised). Verify two things and record both: (1) Claude can invoke a real forwarded Fusion tool; (2) **whether that invocation surfaces as an ACP `session/request_permission` (gated) or is invoked autonomously inside the bridge (gate bypassed)** — this is the security-critical answer (OQ1/security F3). If `mcpServers` is ignored, OR tool calls bypass the gate with no mitigation, Route A is blocked → escalate to upstream bridge/ACP work (mandatory-`-p`: no `-p` fallback). This is a hard go/no-go gate; it is **necessary but not sufficient** — see U14 for the internal blockers. **Test scenarios:** `Test expectation: none -- spike; the deliverable is a recorded go/no-go decision (with the gate-traversal answer), not shipped code.` +**FN-6465 status (2026-06-14):** **UNRESOLVED / BLOCKED**. The original FN-6459 decision was not recovered, and this task did not complete an authenticated, instrumented bridge spike with the real `mcp-config.ts` output. U9 remains a hard NOT-GO gate: do not implement U10-U13 until a follow-up proves both forwarded-tool invocation and ACP permission-gate traversal (or records a definitive no-go/escalation). + ### U14. Design-confirmation: resolve Route A's internal blockers (Route A gate 2 of 2) **Goal:** Resolve the internal blockers that no spike screens — knowable today — before committing U10–U13. **KTD9, KTD10, KTD11.** @@ -313,6 +316,12 @@ plugins/fusion-plugin-acp-runtime/src/ 3. **Per-route posture (KTD9):** confirm the `acp-claude` second runtime id (bridge-pinned, tool-bearing) vs. a per-call override, and how lanes select it (model-id/`useClaudeCli` → `runtimeHint`). **Test scenarios:** `Test expectation: none -- design gate; deliverable is the recorded mechanisms that unblock U10/U11.` +**FN-6465 U14 confirmation (2026-06-14):** **GO for the internal design mechanisms, subject to U9.** Current source still matches the planned seams: + +- **KTD10 / pi-extension injection seam:** `packages/engine/src/pi.ts:1366-1422` is the provider-registration seam (`registerExtensionProviders`) that discovers the vendored `@fusion/pi-claude-cli` and registers pending providers into the pi `ModelRegistry`. The implementation task should construct/inject an ACP bridge client at this engine-owned seam and thread it through the provider options just as `packages/pi-claude-cli/index.ts:222-234` currently threads `mcpConfigPath` into `streamViaCli`; `packages/pi-claude-cli/src/provider.ts:73-77` reads that option shape and `provider.ts:136-156` passes it to the subprocess layer. Add the ACP client/driver as the analogous option field so `@fusion/pi-claude-cli` stays dependency-clean and never imports `@fusion/engine` or plugin internals. +- **KTD11 / `AgentRuntimeOptions.mcpServers` contract:** `packages/engine/src/agent-runtime.ts:35-106` currently has no `mcpServers` option, and the plugin-local structural copy at `plugins/fusion-plugin-acp-runtime/src/types.ts:81-95` mirrors only the fields the runtime reads. `plugins/fusion-plugin-acp-runtime/src/provider.ts:348-356` still hardcodes `mcpServers: []` in `newAcpSession`, and `plugins/fusion-plugin-acp-runtime/src/runtime-adapter.ts:85-89` calls `newAcpSession(connection, { cwd })` without MCP data. U10 should add an optional `mcpServers` field to both option types, change `newAcpSession` to accept it, have `runtime-adapter.ts` pass it through, and default to `[]` when absent for Route-B back compatibility. The existing `packages/pi-claude-cli/src/mcp-config.ts` output is one stdio server under `mcpServers.custom-tools` with `{ command: "node", args: [serverPath, schemaFilePath] }`, which maps directly to an ACP `mcpServers` entry. +- **KTD9 / per-route posture:** `plugins/fusion-plugin-acp-runtime/src/index.ts:13-24` still exposes one global runtime id (`acp`) whose `acpRuntimeFactory` constructs one `AcpRuntimeAdapter` from a frozen settings blob; `plugins/fusion-plugin-acp-runtime/src/runtime-adapter.ts:29-35` resolves that blob once in the adapter constructor. Route A therefore needs a distinct `acp-claude` runtime id/posture pinned to the bridge and tool-bearing defaults rather than a per-call override of the generic `acp` runtime. Lanes should select it through the existing model/provider selection path (`pi-claude-cli` / `useClaudeCli` resolving to a Route-A `runtimeHint`), leaving the generic `acp` contract available for arbitrary ACP agents and Route-B read-only asks. + ### U10. ACP MCP-server forwarding in the runtime (Route A enabler) **Goal:** Forward Fusion's MCP server(s) on `session/new` so the agent can call Fusion tools — implementing the contract change KTD11 specifies.