*/
@@ -89,6 +91,19 @@ console.log(`Integrity verified (${integrity.slice(0, 20)}...).`);
const memberPath = `package/prebuilds/${classifier}/runtime.node`;
execFileSync('tar', ['-xzf', tarballPath, '-C', outDir, memberPath], { stdio: 'inherit' });
fs.renameSync(path.join(outDir, memberPath), runtimePath);
+
+// Extract the copilot CLI executable (necessary-and-sufficient runtime artifact invariant:
+// host_start needs both runtime.node and the copilot CLI from the same package version).
+const isWindows = classifier.startsWith('win32');
+const cliTarballMember = isWindows ? 'package/copilot.exe' : 'package/copilot';
+const cliFilename = isWindows ? 'copilot.exe' : 'copilot';
+const cliPath = path.join(resourceDir, cliFilename);
+execFileSync('tar', ['-xzf', tarballPath, '-C', outDir, cliTarballMember], { stdio: 'inherit' });
+fs.renameSync(path.join(outDir, cliTarballMember), cliPath);
+if (!isWindows) {
+ fs.chmodSync(cliPath, 0o755);
+}
+
fs.rmSync(path.join(outDir, 'package'), { recursive: true, force: true });
fs.rmSync(tarballPath, { force: true });
diff --git a/java/sdk/src/main/java/com/github/copilot/CopilotClient.java b/java/sdk/src/main/java/com/github/copilot/CopilotClient.java
index f420585be7..9aad53ee49 100644
--- a/java/sdk/src/main/java/com/github/copilot/CopilotClient.java
+++ b/java/sdk/src/main/java/com/github/copilot/CopilotClient.java
@@ -474,25 +474,12 @@ private static InProcessTransport openInProcessTransport(CopilotClientOptions op
}
/**
- * Resolves the runtime entrypoint handed to the in-process host. Callers do not
- * configure this: the bundled runtime is used unless an explicit override is
- * present in the environment.
+ * Resolves the runtime entrypoint handed to the in-process host. The copilot
+ * CLI executable is resolved from the same bundled location as
+ * {@code runtime.node} — no environment variables or PATH search.
*/
private static String resolveInProcessEntrypoint(CopilotClientOptions options) throws IOException {
- String envPath = System.getenv(NativeRuntimeLoader.COPILOT_CLI_PATH_ENV);
- if (envPath != null && !envPath.isBlank()) {
- return envPath;
- }
- String cliPath = options.getCliPath();
- if (cliPath != null && !cliPath.isBlank()) {
- return cliPath;
- }
- String discovered = NativeRuntimeLoader.findRuntimeOnPath();
- if (discovered != null) {
- return discovered;
- }
- throw new IOException("The in-process runtime could not be located. Add the runtime artifact for this"
- + " platform to the classpath, or use a child-process connection.");
+ return NativeRuntimeLoader.resolveEntrypoint().toString();
}
private static void closeRuntimeHost(AutoCloseable host) {
diff --git a/java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java b/java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java
index edc58284eb..797c8e9aed 100644
--- a/java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java
+++ b/java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java
@@ -37,6 +37,8 @@
public final class NativeRuntimeLoader {
static final String RUNTIME_FILENAME = "runtime.node";
+ static final String CLI_FILENAME = "copilot";
+ static final String CLI_FILENAME_WINDOWS = "copilot.exe";
/** Environment variable that overrides where the runtime is loaded from. */
public static final String COPILOT_CLI_PATH_ENV = "COPILOT_CLI_PATH";
static final String VERSION_RESOURCE = "copilot-runtime.properties";
@@ -117,6 +119,33 @@ public static Path resolve() throws IOException {
return resolve(null, findRuntimeOnPath(), cacheBase, loader, classifier, version);
}
+ /**
+ * Resolves the copilot CLI executable from the same location as the bundled
+ * {@code runtime.node}. The CLI is used as {@code argv[0]} in
+ * {@code copilot_runtime_host_start} — the Rust runtime spawns it as a child
+ * process.
+ *
+ *
+ * This method calls {@link #resolve()} to locate {@code runtime.node}, then
+ * looks for the {@code copilot} executable in the same directory. Both
+ * artifacts are extracted from the classifier JAR together.
+ *
+ * @return absolute path to the {@code copilot} CLI executable
+ * @throws IOException
+ * if the CLI executable cannot be located
+ */
+ public static Path resolveEntrypoint() throws IOException {
+ Path runtimePath = resolve();
+ Path parent = runtimePath.getParent();
+ String cliName = isWindows() ? CLI_FILENAME_WINDOWS : CLI_FILENAME;
+ Path cliPath = parent.resolve(cliName);
+ if (Files.isRegularFile(cliPath) && Files.size(cliPath) > 0) {
+ return cliPath;
+ }
+ throw new IOException("Copilot CLI executable not found at " + cliPath
+ + " — the classifier JAR must contain both runtime.node and the copilot binary");
+ }
+
/**
* Reads the SDK version from the filtered {@code copilot-runtime.properties}
* resource.
@@ -259,6 +288,7 @@ static Path extractToCache(Path cacheBase, ClassLoader loader, String classifier
// Step 1 — fast path: return an existing valid cache entry.
if (isValidCachedFile(cached)) {
+ extractCliToCache(cacheDir, loader, classifier, publisher);
return cached;
}
@@ -281,9 +311,53 @@ static Path extractToCache(Path cacheBase, ClassLoader loader, String classifier
tryDelete(temp);
}
+ // Step 5 — also extract the copilot CLI executable alongside runtime.node.
+ extractCliToCache(cacheDir, loader, classifier, publisher);
+
return cached;
}
+ /**
+ * Extracts the copilot CLI executable from the classpath to the same cache
+ * directory as {@code runtime.node}. Idempotent — skips extraction if already
+ * present and valid.
+ */
+ static void extractCliToCache(Path cacheDir, ClassLoader loader, String classifier, AtomicPublisher publisher)
+ throws IOException {
+ String cliName = isWindows() ? CLI_FILENAME_WINDOWS : CLI_FILENAME;
+ String cliResourcePath = "native/" + classifier + "/" + cliName;
+ Path cachedCli = cacheDir.resolve(cliName);
+
+ if (isValidCachedFile(cachedCli)) {
+ return;
+ }
+
+ URL cliResource = loader.getResource(cliResourcePath);
+ if (cliResource == null) {
+ // CLI not on classpath — this is allowed for the COPILOT_CLI_PATH fallback
+ // path but will fail later in resolveEntrypoint() if InProcess is selected.
+ return;
+ }
+
+ Files.createDirectories(cacheDir);
+ Path temp = Files.createTempFile(cacheDir, "cli-tmp-", "");
+ try {
+ copyResourceToTemp(cliResource, cliResourcePath, temp);
+ publisher.publish(temp, cachedCli);
+ } finally {
+ tryDelete(temp);
+ }
+
+ // Set executable permission on non-Windows systems.
+ if (!isWindows()) {
+ try {
+ cachedCli.toFile().setExecutable(true, false);
+ } catch (SecurityException ignored) {
+ // Best-effort; the file may already be executable from the temp copy.
+ }
+ }
+ }
+
/**
* Tries source 2 (classpath extraction) first and falls back to source 3
* (bundled-CLI sibling) only when the classpath resource is absent.
diff --git a/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java b/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java
index f040607353..5ac4bde7c9 100644
--- a/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java
+++ b/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java
@@ -391,7 +391,6 @@ private Map buildInProcessEnvironment(CopilotClientOptions optio
env.putAll(optionEnvironment);
options.setEnvironment(null);
}
- env.put("COPILOT_CLI_PATH", cliPath);
return env;
}
From e4a1e0c2e293db21d4e1bac8f027fe933e344d33 Mon Sep 17 00:00:00 2001
From: Ed Burns
Date: Fri, 7 Aug 2026 01:38:33 +0000
Subject: [PATCH 5/7] Fix InProcess test parity: respect explicit subprocess
options over env var
- resolveDefaultConnection: when cliUrl, cliPath, or port are explicitly
set, fall back to subprocess transport even if COPILOT_SDK_DEFAULT_CONNECTION
is 'inprocess'. Explicit options take precedence over the env var default.
- validateEnvironmentOptions: check isEmpty() in addition to null, since
setEnvironment(null) clears the map rather than nulling the field.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7a38160-a65e-4d0c-9087-4f28da2a51b8
---
.../main/java/com/github/copilot/CopilotClient.java | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/java/sdk/src/main/java/com/github/copilot/CopilotClient.java b/java/sdk/src/main/java/com/github/copilot/CopilotClient.java
index 9aad53ee49..8e23e666ab 100644
--- a/java/sdk/src/main/java/com/github/copilot/CopilotClient.java
+++ b/java/sdk/src/main/java/com/github/copilot/CopilotClient.java
@@ -259,6 +259,16 @@ private static RuntimeConnection resolveDefaultConnection(CopilotClientOptions o
static RuntimeConnection resolveDefaultConnection(CopilotClientOptions options, String envValue) {
if (envValue != null && !envValue.isEmpty()) {
if ("inprocess".equalsIgnoreCase(envValue)) {
+ // Explicit subprocess options take precedence over the env var default.
+ if (options.getCliUrl() != null && !options.getCliUrl().isEmpty()) {
+ return inferConnectionFromOptions(options);
+ }
+ if (options.getCliPath() != null && !options.getCliPath().isEmpty()) {
+ return inferConnectionFromOptions(options);
+ }
+ if (options.getPort() != 0) {
+ return inferConnectionFromOptions(options);
+ }
return RuntimeConnection.forInProcess();
}
if (!"stdio".equalsIgnoreCase(envValue)) {
@@ -390,7 +400,7 @@ private static void validateEnvironmentOptions(CopilotClientOptions options, Run
return;
}
- rejectInProcessOption("Environment", options.getEnvironment() != null,
+ rejectInProcessOption("Environment", options.getEnvironment() != null && !options.getEnvironment().isEmpty(),
"set the variables on the host process environment instead");
rejectInProcessOption("Telemetry", options.getTelemetry() != null,
"configure telemetry through the host process environment instead");
From b78e74ef5f334bba7c2d740563ff81ad8b187eba Mon Sep 17 00:00:00 2001
From: Ed Burns
Date: Fri, 7 Aug 2026 01:45:10 +0000
Subject: [PATCH 6/7] GUTDODP
---
...ntic-01-test-parity-fix-remaining-tests.md | 125 ++++++++++++++++++
1 file changed, 125 insertions(+)
create mode 100644 1917-java-embed-rust-cli-runtime-remove-before-merge/post-agentic-01-test-parity-fix-remaining-tests.md
diff --git a/1917-java-embed-rust-cli-runtime-remove-before-merge/post-agentic-01-test-parity-fix-remaining-tests.md b/1917-java-embed-rust-cli-runtime-remove-before-merge/post-agentic-01-test-parity-fix-remaining-tests.md
new file mode 100644
index 0000000000..e80087baab
--- /dev/null
+++ b/1917-java-embed-rust-cli-runtime-remove-before-merge/post-agentic-01-test-parity-fix-remaining-tests.md
@@ -0,0 +1,125 @@
+# Fix remaining InProcess test parity failures
+
+## Context
+
+Branch: `edburns/review-copilot-pr-2272` (local worktree at `copilot-sdk-01`)
+Push target: `git push upstream HEAD:copilot/edburns1917-java-embed-rust-cli-runtime-post-agent`
+
+The `-Pinprocess` Maven profile sets `COPILOT_SDK_DEFAULT_CONNECTION=inprocess`, which forces all E2E tests to use the InProcess FFI transport instead of subprocess. Most tests now pass. 24 tests still fail in two categories.
+
+## Category 1: Tests that set `cwd` or `cliArgs` on options
+
+These tests go through `ctx.createClient(options)` → `E2ETestContext.applyContextOptions()`. The InProcess branch absorbs `environment` into `InProcessEnvGuard` and nulls it, but does NOT do the same for `cwd` or `cliArgs`. The `CopilotClient` constructor then calls `validateEnvironmentOptions()` which rejects non-null `cwd`/`cliArgs` for InProcess.
+
+**Fix:** In `E2ETestContext.applyContextOptions()`, when InProcess mode is detected, also null out `cwd` and `cliArgs` before constructing the client. For `cwd`, it's meaningless in InProcess (host process cwd is already set). For `cliArgs`, they're subprocess-specific flags.
+
+Location: `java/sdk/src/test/java/com/github/copilot/E2ETestContext.java` lines 354-376
+
+Current InProcess branch in `applyContextOptions`:
+```java
+if (isInProcessMode(options)) {
+ InProcessEnvGuard guard = new InProcessEnvGuard(buildInProcessEnvironment(options));
+ inProcessEnvGuards.add(guard);
+ try {
+ options.setEnvironment(null);
+ return new CopilotClient(options, guard::close);
+ } catch (RuntimeException e) {
+ guard.close();
+ throw e;
+ }
+}
+```
+
+Needs to also null `cwd` and `cliArgs`:
+```java
+options.setEnvironment(null);
+options.setCwd(null);
+options.setCliArgs(null);
+```
+
+Affected tests: `PerSessionAuthTest` (sets cwd+environment), possibly others.
+
+## Category 2: StreamingFidelityTest hang
+
+`StreamingFidelityTest.testShouldEmitStreamingDeltasWithReasoningEffortConfigured` hangs indefinitely in InProcess mode. The main thread is blocked on `CompletableFuture.get()` at line 258. The JSON-RPC reader thread is reading from `QueueInputStream` (the InProcess FFI receive stream) but never receives the expected response.
+
+This is a functional issue, not a validation issue. The replay proxy is running (CapiProxy thread is active), but the InProcess transport isn't completing the streaming interaction.
+
+Diagnosis approach:
+1. Check if the test's replay snapshot exists and is correct for streaming
+2. Check if `host_start` succeeds for this test (serverHandle != 0)
+3. jstack showed the reader thread blocked in `QueueInputStream.read()` — no data arriving via the FFI callback
+4. Possible causes: the replay proxy response format doesn't match what the InProcess runtime expects for streaming, or the connection isn't routing correctly through the replay proxy
+
+## Key architectural facts
+
+- `runtime.node` is loaded via JNA. `copilot` CLI binary is spawned as child by `host_start` via `argv[0]`.
+- Both are now bundled in the classifier JAR at `native//runtime.node` and `native//copilot`.
+- `NativeRuntimeLoader.resolve()` extracts both to `~/.copilot/runtime-cache///`.
+- `NativeRuntimeLoader.resolveEntrypoint()` finds `copilot` alongside `runtime.node`.
+- `CopilotClient.resolveInProcessEntrypoint()` simply calls `NativeRuntimeLoader.resolveEntrypoint().toString()`.
+- `InProcessEnvGuard` uses JNA `libc.setenv()` to mutate the native process env (not visible to `System.getenv()`).
+- The replay proxy (CapiProxy) runs as a Node.js subprocess serving YAML snapshot responses.
+
+## CopilotClientOptions.setEnvironment(null) quirk
+
+`setEnvironment(null)` does NOT set the field to null — it calls `this.environment.clear()`, leaving an empty HashMap. `getEnvironment()` then returns a non-null empty map. The validation now checks `!isEmpty()` too (already fixed).
+
+Similarly, check if `setCwd(null)` / `setCliArgs(null)` have similar behavior. If `setCwd(null)` doesn't actually null the field, the validation might still fire.
+
+## Validation in CopilotClient constructor
+
+```java
+private static void validateEnvironmentOptions(CopilotClientOptions options, RuntimeConnection connection) {
+ if (!(connection instanceof InProcessRuntimeConnection)) return;
+ rejectInProcessOption("Environment", options.getEnvironment() != null && !options.getEnvironment().isEmpty(), ...);
+ rejectInProcessOption("Telemetry", options.getTelemetry() != null, ...);
+ rejectInProcessOption("Cwd", options.getCwd() != null, ...);
+ rejectInProcessOption("CliArgs", options.getCliArgs() != null && options.getCliArgs().length > 0, ...);
+}
+```
+
+## resolveDefaultConnection precedence (already fixed)
+
+When `COPILOT_SDK_DEFAULT_CONNECTION=inprocess` but `cliUrl`/`cliPath`/`port` are explicitly set, the explicit options win and subprocess transport is used. Tests like `McpAuthInterestRegistrationTest` that create `new CopilotClient(options.setCliUrl(...))` directly now correctly bypass InProcess.
+
+## Full list of 24 failing test methods
+
+```
+ByokBearerTokenProviderE2ETest (3 methods)
+CopilotRequestCancelErrorE2ETest (2)
+CopilotRequestHandlerE2ETest (2)
+CopilotRequestSessionIdE2ETest (1)
+GitHubTelemetryTest (2)
+McpAuthInterestRegistrationTest (3)
+ModeHandlersTest (2)
+PerSessionAuthTest (3)
+ProviderEndpointE2ETest (2)
+RpcServerE2ETest (1 - testShouldAddSecretFilterValues — NOW PASSES)
+SessionConfigE2ETest (2)
+StreamingFidelityTest (1 - hangs)
+SubagentHooksE2ETest (1)
+```
+
+## Commands
+
+```bash
+# Run all tests with InProcess
+cd java && mvn clean verify -Pinprocess
+
+# Run specific failing tests
+COPILOT_SDK_DEFAULT_CONNECTION=inprocess mvn test -pl sdk -Dtest="PerSessionAuthTest,StreamingFidelityTest" -DfailIfNoTests=false
+
+# Format before commit
+mvn spotless:apply
+
+# Push
+git push upstream HEAD:copilot/edburns1917-java-embed-rust-cli-runtime-post-agent
+```
+
+## Java env bootstrap (required before any mvn/java command)
+```bash
+export JAVA_HOME="/usr/lib/jvm/msopenjdk-25-amd64"
+export M2_HOME="${HOME}/Downloads/apache-maven-3.9.8"
+export PATH="${M2_HOME}/bin:${JAVA_HOME}/bin:${PATH}"
+```
From 9fe28a8aeb3b183f6ed176a32c464bf57e901b60 Mon Sep 17 00:00:00 2001
From: Ed Burns
Date: Fri, 7 Aug 2026 17:29:06 +0000
Subject: [PATCH 7/7] Fix Java in-process test lifecycle and parity
Prevent the Java in-process test profile from corrupting Surefire control
streams or poisoning later tests through the runtime's process-global LLM
provider registration. Preserve explicit subprocess and TCP transport choices,
sanitize process-only options before constructing in-process clients, and run
request-handler tests over their required isolated stdio runtime.
Fix the remaining test-contract issues by making fake socket RPC handler
registration atomic with reader startup, honoring the configured CLI
entrypoint when runtime.node is in a prebuilds directory, and isolating the
streaming model-cache scenario. Remove in-process skip annotations from tests
that already exercise an explicit subprocess transport.
The complete `mvn clean verify -Pinprocess` run now finishes successfully
without hangs, transport timeouts, provider-ownership failures, or Surefire
stream corruption.
File-by-file manifest:
- `java/sdk/pom.xml`: use Surefire's TCP fork channel for unit and integration
tests so native runtime output cannot corrupt Maven's process-pipe protocol.
- `java/sdk/src/main/java/com/github/copilot/CopilotClient.java`: preserve
explicitly selected TCP options when the default connection environment
requests in-process transport.
- `java/sdk/src/main/java/com/github/copilot/JsonRpcClient.java`: add a socket
construction hook that registers handlers before the reader thread starts.
- `java/sdk/src/main/java/com/github/copilot/ffi/NativeRuntimeLoader.java`:
resolve the configured Copilot executable separately from runtime.node when
the native library uses the package's prebuilds layout.
- `java/sdk/src/main/java/com/github/copilot/rpc/CopilotClientOptions.java`:
allow `setCwd(null)` to clear a previously configured working directory.
- `java/sdk/src/test/java/com/github/copilot/ClientOptionsE2ETest.java`: run
explicit fake-stdio option forwarding tests under the in-process profile.
- `java/sdk/src/test/java/com/github/copilot/ConfigCloneTest.java`: cover
clearing a configured working directory.
- `java/sdk/src/test/java/com/github/copilot/CopilotClientTest.java`: remove
obsolete in-process skips from explicit subprocess and TCP lifecycle tests.
- `java/sdk/src/test/java/com/github/copilot/CopilotClientTransportTest.java`:
test explicit transport precedence, in-process option sanitization, and TCP
token selection under the profile default.
- `java/sdk/src/test/java/com/github/copilot/CopilotRequestTestSupport.java`:
explicitly select stdio for request-handler tests that register the
process-global LLM inference provider.
- `java/sdk/src/test/java/com/github/copilot/E2ETestContext.java`: honor
explicit transports, route request-handler clients to subprocess isolation,
and clear environment, cwd, and CLI arguments before in-process client
construction.
- `java/sdk/src/test/java/com/github/copilot/GitHubTelemetryTest.java`: register
fake runtime RPC handlers before socket message processing begins.
- `java/sdk/src/test/java/com/github/copilot/MetadataApiTest.java`: run explicit
stdio metadata tests instead of skipping them under the profile.
- `java/sdk/src/test/java/com/github/copilot/PerSessionAuthTest.java`: run the
explicit subprocess unauthenticated case under the profile.
- `java/sdk/src/test/java/com/github/copilot/RpcServerMiscE2ETest.java`: run the
explicit subprocess account lifecycle case under the profile.
- `java/sdk/src/test/java/com/github/copilot/StreamingFidelityTest.java`: give
the gpt-5.4 reasoning/streaming scenario an isolated proxy and runtime model
cache.
- `java/sdk/src/test/java/com/github/copilot/ffi/FfiRuntimeHostTest.java`: cover
failed connection-open cleanup followed by successful sequential startup.
- `java/sdk/src/test/java/com/github/copilot/ffi/NativeRuntimeLoaderTest.java`:
cover resolving a configured CLI beside a prebuilds runtime.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e03c4e94-97b0-41ad-9f4e-c01633dc0bf7
---
...c-01-test-parity-fix-remaining-tests-01.md | 172 ++++++++++++++++++
java/sdk/pom.xml | 2 +
.../com/github/copilot/CopilotClient.java | 3 +
.../com/github/copilot/JsonRpcClient.java | 13 ++
.../copilot/ffi/NativeRuntimeLoader.java | 14 +-
.../copilot/rpc/CopilotClientOptions.java | 6 +-
.../github/copilot/ClientOptionsE2ETest.java | 5 -
.../com/github/copilot/ConfigCloneTest.java | 9 +
.../com/github/copilot/CopilotClientTest.java | 16 --
.../copilot/CopilotClientTransportTest.java | 32 ++--
.../copilot/CopilotRequestTestSupport.java | 3 +-
.../com/github/copilot/E2ETestContext.java | 10 +-
.../github/copilot/GitHubTelemetryTest.java | 33 ++--
.../com/github/copilot/MetadataApiTest.java | 4 -
.../github/copilot/PerSessionAuthTest.java | 3 -
.../github/copilot/RpcServerMiscE2ETest.java | 3 -
.../github/copilot/StreamingFidelityTest.java | 46 ++---
.../copilot/ffi/FfiRuntimeHostTest.java | 45 +++++
.../copilot/ffi/NativeRuntimeLoaderTest.java | 10 +
19 files changed, 339 insertions(+), 90 deletions(-)
create mode 100644 1917-java-embed-rust-cli-runtime-remove-before-merge/post-agentic-01-test-parity-fix-remaining-tests-01.md
diff --git a/1917-java-embed-rust-cli-runtime-remove-before-merge/post-agentic-01-test-parity-fix-remaining-tests-01.md b/1917-java-embed-rust-cli-runtime-remove-before-merge/post-agentic-01-test-parity-fix-remaining-tests-01.md
new file mode 100644
index 0000000000..f4c9bc3ad0
--- /dev/null
+++ b/1917-java-embed-rust-cli-runtime-remove-before-merge/post-agentic-01-test-parity-fix-remaining-tests-01.md
@@ -0,0 +1,172 @@
+# Prompt: make the Java InProcess test run clean
+
+You are working in `/home/edburns/workareas/copilot-sdk-01`, branch
+`edburns/review-copilot-pr-2272`. Read these files first:
+
+- `1917-java-embed-rust-cli-runtime-remove-before-merge/post-agentic-01-test-parity-fix-remaining-tests.md`
+- `java/20260807-0145-job-logs.txt`
+- the current git diff and the Java test/runtime/harness sources
+
+The target command is:
+
+```bash
+cd java
+mvn clean verify -Pinprocess
+```
+
+Make the implementation and test changes necessary for a genuinely clean,
+non-hanging run. Do not solve this by broadly skipping tests, increasing
+timeouts, weakening assertions, or hiding errors. Preserve the negative-test
+assertions; expected negative cases may be logged, but they must not be
+reported as test errors.
+
+## What the interrupted log establishes
+
+The run was interrupted after more than an hour; it has no `BUILD SUCCESS`.
+There are 88 errors in 20 suites. The failures are highly clustered:
+
+- `std/in stream corrupted` appears during `AskUserTest`.
+- `ByokBearerTokenProviderE2ETest` has the expected fake 404 in one negative
+ case, but the other two tests fail because
+ `llmInference.setProvider` says “Another client is already the LLM inference
+ provider.”
+- The same provider-ownership error breaks
+ `CopilotRequestCancelErrorE2ETest`, `CopilotRequestHandlerE2ETest`,
+ `SessionConfigE2ETest`, and other provider/handler tests.
+- `CompactionTest`, `CopilotSessionTest`, `ErrorHandlingTest`,
+ `EventFidelityTest`, `ExecutorWiringTest`, `HooksTest`, `McpAndAgentsTest`,
+ `ModeHandlersTest`, `MultiProviderRegistryE2ETest`, `PermissionsTest`,
+ `PreMcpToolCallHookTest`, `RpcSessionStateExtrasE2ETest`,
+ `SessionConfigE2ETest`, and `SessionEventsE2ETest` contain repeated
+ approximately 60-second `sendAndWait`/future timeouts.
+- `GitHubTelemetryTest` fails immediately because an InProcess connection
+ receives `Method not found: connect` and `Method not found: ping`; determine
+ whether this test must explicitly use the subprocess/socket transport or
+ whether the InProcess endpoint is missing required handlers.
+- `RpcServerE2ETest` has a 30-second RPC timeout and
+ `RpcSessionStateExtrasE2ETest` has a 60-second timeout.
+- `PerSessionAuthTest` has one skipped test and a negative 401 “Bad
+ credentials” trace. The test itself is not an error.
+- `ClientOptionsE2ETest` skips all three tests. Other suites also report
+ intentional-looking skips: `CopilotClientTest` (14),
+ `CopilotClientTransportTest` (4), `MetadataApiTest` (3),
+ `RpcServerMiscE2ETest` (1), and `CompactionTest` (1).
+- Many stack traces in `CreateSessionReKeyEntryTest`, `JsonRpcClientTest`,
+ `LifecycleEventManagerTest`, `RpcHandlerDispatcherTest`, and
+ `SessionHandlerTest` are deliberately generated negative-test traces and
+ are followed by passing summaries. Do not misclassify them as failures.
+
+## Priority 1: stop stream corruption and fix InProcess ownership/lifecycle
+
+Investigate `std/in stream corrupted` first. Trace every process and stream
+created by the InProcess FFI path, `host_start`, the bundled `copilot`
+entrypoint, `NativeRuntimeLoader`, `InProcessRuntimeConnection`, `CapiProxy`,
+and Surefire. Identify which native/child process is writing bytes to the
+Surefire-controlled stdout/stdin protocol. Ensure child stdout/stderr are
+consumed or redirected in the same way as the supported transport and that
+the FFI receive/send streams are not closed or reused by another client.
+Do not merely suppress Surefire output.
+
+Then fix the “Another client is already the LLM inference provider” root
+cause. Determine whether clients, native hosts, provider registrations, or
+`InProcessEnvGuard` instances survive test teardown. Verify the close path on
+both successful and failed `start()`, failed `createSession()`, and failed
+requests. Ensure a failed startup cannot leave a provider registered and that
+each test context closes its client/proxy/runtime deterministically. If the
+InProcess runtime is process-global, serialize or otherwise coordinate provider
+ownership rather than allowing overlapping providers. Add focused regression
+coverage for failed-start cleanup and sequential client startup.
+
+The earlier context notes that `E2ETestContext.applyContextOptions()` must
+clear InProcess-incompatible `cwd` and `cliArgs` in addition to `environment`.
+Implement that carefully, and verify the actual setter semantics:
+`setEnvironment(null)` clears to an empty map, while `setCwd(null)` and
+`setCliArgs(null)` must be checked rather than assumed. Add or update tests so
+the options are truly absent according to constructor validation.
+
+## Priority 2: isolate and repair the common timeout
+
+After Priority 1, run small, serial selectors, not the full suite:
+
+```bash
+cd java
+COPILOT_SDK_DEFAULT_CONNECTION=inprocess mvn test -pl sdk \
+ -Dtest="AskUserTest,ByokBearerTokenProviderE2ETest,CopilotSessionTest" \
+ -DfailIfNoTests=false
+```
+
+Use a bounded shell timeout while debugging so a regression cannot consume an
+hour. For any remaining timeout, capture a thread dump and inspect the
+corresponding Surefire report plus replay-proxy output. Follow one request
+from Java JSON-RPC send, through the FFI callback/`QueueInputStream`, into the
+replay proxy, and back to the Java reader. Confirm that:
+
+1. `host_start` returns a valid handle and the child `copilot` entrypoint is
+ reachable.
+2. The request reaches the proxy with the expected snapshot.
+3. Every response/event is framed correctly and enqueued to the receive
+ stream.
+4. stream completion/EOF and client close wake blocked readers.
+5. callbacks do not depend on a thread or executor that has already shut down.
+
+Use `StreamingFidelityTest.testShouldEmitStreamingDeltasWithReasoningEffortConfigured`
+as the minimal streaming reproducer, but also test one ordinary
+`CopilotSessionTest` request. Do not patch each timed-out suite individually;
+the repeated 60-second failures indicate a shared transport or lifecycle
+defect. Once the common path works, rerun representative handler, hook,
+permission, event, session-config, MCP, and RPC-server selectors and only
+then the complete profile.
+
+`GitHubTelemetryTest` is a separate transport-contract issue: inspect its
+test setup and the supported connection mode. If it intentionally uses a
+minimal fake RPC peer that only supports telemetry, make it explicitly select
+that transport so the global InProcess profile cannot route it to a runtime
+without `connect`/`ping`. If InProcess is intended, implement the missing
+protocol surface and add focused coverage.
+
+## Priority 3: remove unjustified skips
+
+Audit every skipped test in the log and the associated assumptions. For each:
+
+- make it run under InProcess when the behavior is transport-independent;
+- explicitly force subprocess/socket transport when the test is specifically
+ validating subprocess-only options or protocol behavior; or
+- change the test setup so the same public behavior is exercised through
+ InProcess.
+
+Do not add a profile-wide exclusion and do not convert skipped tests to
+passing assertions. In particular, investigate all three
+`ClientOptionsE2ETest` skips, the `PerSessionAuthTest` skip, and the skips in
+`CopilotClientTest`, `CopilotClientTransportTest`, `MetadataApiTest`,
+`RpcServerMiscE2ETest`, and `CompactionTest`. The final profile run should
+have zero skips unless a test is demonstrably impossible on the platform and
+the repository’s existing policy explicitly permits it; document any
+remaining exception in the test source.
+
+## Priority 4: make expected negative output intentional
+
+Do not alter assertions for negative tests. After all tests pass, reduce noisy
+expected stack-trace logging only where the repository’s logging conventions
+support it: distinguish expected test-triggered failures from unexpected
+transport failures, and avoid logging full stack traces at warning/error for
+the expected path if that can be done without hiding real failures. The
+`fake byok endpoint`, `401 Bad credentials`, `session.resume` not-found,
+handler exceptions, malformed JSON, socket-close, and re-key traces must
+remain asserted and diagnosable.
+
+## Validation and completion criteria
+
+Use the repository’s normal Java bootstrap and Maven logging conventions.
+Format Java changes with `mvn spotless:apply` from `java`. Run focused tests
+after each root-cause fix, then:
+
+```bash
+cd java
+mvn clean verify -Pinprocess
+```
+
+The task is complete only when this command terminates normally with
+`BUILD SUCCESS`, all test suites report zero failures and zero errors, no
+test hangs or 60-second transport timeouts occur, no Surefire stream
+corruption occurs, and the skip count is zero or each explicitly justified
+platform exception is documented and approved by the existing test policy.
diff --git a/java/sdk/pom.xml b/java/sdk/pom.xml
index 12cb42a3ee..1afcf9c9be 100644
--- a/java/sdk/pom.xml
+++ b/java/sdk/pom.xml
@@ -243,6 +243,7 @@
+
${project.build.directory}
${project.build.finalName}
@@ -264,6 +265,7 @@
maven-surefire-plugin
alphabetical
+
${testExecutionAgentArgs} ${surefire.jvm.args} --add-opens com.github.copilot.java/com.github.copilot.e2e=ALL-UNNAMED