` before OpenSSH's `--`
+ separator. The purpose contract compares the complete diagnostic vector with an independently
+ built production vector, rejects `StrictHostKeyChecking=no`, and proves connection reuse and all
+ production arguments are unchanged.
+- Syntax/focused evidence: both launcher scripts pass `node --check`.
+ `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1
+src/main/ssh/ssh-connection.test.ts src/main/ssh/ssh-system-fallback.test.ts
+src/main/ssh/ssh-system-no-input-windows-openssh.test.ts
+src/main/ssh/ssh-relay-runtime-windows-system-ssh-openssh-full-size.test.ts
+config/scripts/ssh-relay-runtime-windows-no-input-launcher.test.mjs
+config/scripts/ssh-relay-runtime-workflow.test.mjs` passes 120 runnable cases with ten declared
+ native/live skips in 3.13 seconds real; maximum RSS is 174,571,520 bytes and peak footprint is
+ 97,113,848 bytes.
+- Release/static evidence: the unquoted release-contract command passes 51 files and 285 runnable
+ cases with eight declared Windows skips in 16.23 seconds; maximum RSS is 196,100,096 bytes and
+ peak footprint is 97,179,360 bytes. `/usr/bin/time -l pnpm typecheck` passes in 3.38 seconds real
+ with 1,208,680,448-byte maximum RSS and 97,031,952-byte peak footprint. `/usr/bin/time -l pnpm
+lint` passes in 18.59 seconds real with the 26 existing warnings, all 41 reliability gates, and
+ the 355-entry max-lines ratchet; maximum RSS is 2,027,831,296 bytes and peak footprint is
+ 97,392,520 bytes.
+- Residual boundary: local execution does not prove the fixture path is accepted by Win32-OpenSSH,
+ authentication completes, the launcher exits naturally, full-size transfer runs, or the fixture
+ profile tears down. Commit/push only this correction and require exact-head x64/ARM64 evidence.
+ No production caller, Beta, fallback, tuple, publication, default, signing, or SignPath behavior
+ is authorized by this local proof.
+
## Accepted Gaps
No product gap is accepted merely because it appears in this list. Each entry requires explicit
@@ -20018,12 +20086,12 @@ The project is not complete until every applicable item below is checked with ev
## Next Required Action
-Commit and push only the bounded internal-timeout and verbose-output capture recorded by
-`E-M6-WINDOWS-VERBOSE-LIFECYCLE-CAPTURE-LOCAL-001`, then require exact-head Windows x64 and
-ARM64 legacy-compiler, launcher-timeout settlement, verbose-client phase classification, and exact
-profile/directory teardown evidence. Do not
-change the production Windows handle or check the broad Milestone 6 Windows system-SSH item until
-both architectures select the same console-independent strategy. Do not add an
+Commit and push only the explicit diagnostic fixture-trust correction recorded by
+`E-M6-WINDOWS-DIAGNOSTIC-HOST-TRUST-CORRECTION-LOCAL-001`, then require exact-head Windows x64 and
+ARM64 legacy-compiler, launcher, strict host-key authentication, natural client settlement,
+full-size transfer, and exact profile/directory teardown evidence. Do not change the production
+Windows handle or check the broad Milestone 6 Windows system-SSH item until both architectures pass
+the same console-independent strategy. Do not add an
Electron/startup/product importer, per-target mode wiring, fallback, tuple
enablement, release publication, or default behavior.
Keep Node upstream `.tar.xz` inputs, Windows ZIP, `ORCA_RELAY_PATH`, existing desktop required-assets
diff --git a/docs/reference/plans/2026-07-14-ssh-relay-github-release-plan.html b/docs/reference/plans/2026-07-14-ssh-relay-github-release-plan.html
index 44b59a7bcec..a0d81e387e1 100644
--- a/docs/reference/plans/2026-07-14-ssh-relay-github-release-plan.html
+++ b/docs/reference/plans/2026-07-14-ssh-relay-github-release-plan.html
@@ -1669,19 +1669,23 @@
queued console EOF before child creation, and shared that console with the SSH
child while retaining private output pipes, exact handle inheritance, job
ownership, and bounded cancellation. Native x64/arm64 prove the console handle
- and zero-byte cooked EOF but the live client still hangs, falsifying stdin alone.
- The next one-variable diagnostic retained that console stdin and replaced only
- child stdout/stderr pipes with unique delete-on-close regular files under an
- explicit per-stream byte ceiling, bounded polling/cancellation, incremental
+ and zero-byte cooked EOF but the live client still hangs, falsifying stdin
+ alone. The next one-variable diagnostic retained that console stdin and replaced
+ only child stdout/stderr pipes with unique delete-on-close regular files under
+ an explicit per-stream byte ceiling, bounded polling/cancellation, incremental
post-exit replay, and exact cleanup. Native x64/arm64 prove those contracts, but
the live client still hangs with the same lifecycle tuple, falsifying redirected
- output pipes as the remaining cause. Before selecting ConPTY or another SSH
- client, the runner-only launcher must boundedly terminate its own diagnostic
- child and replay an exact verbose OpenSSH trace to classify the stuck client
- phase. Do not package, sign, or add a product caller. POSIX retains ignored
- stdin plus -n; fixture-owned Windows session processes settle
- before profile hives are boundedly unloaded and native profile deletion begins;
- MaxSessions=1; interrupted upload; stale lock
+ output pipes as the remaining cause. The bounded verbose trace on native
+ x64/arm64 then shows that Win32-OpenSSH ignores the workflow's overridden
+ profile variables for host-key discovery and stops before authentication while
+ looking for the runner account's missing default known_hosts.
+ Before selecting ConPTY or another SSH client, pass only the fixture's exact
+ pinned known_hosts path with strict host-key checking and require
+ both architectures to pass. Do not weaken trust, package, sign, or add a product
+ caller. POSIX retains ignored stdin plus -n; fixture-owned Windows
+ session processes settle before profile hives are boundedly unloaded and native
+ profile deletion begins; MaxSessions=1; interrupted upload; stale
+ lock
Bundled Node hashes the full staged tree before sentinel write;
diff --git a/src/main/ssh/ssh-system-no-input-windows-openssh.test.ts b/src/main/ssh/ssh-system-no-input-windows-openssh.test.ts
index f90acfe38f5..2b3f476ccb8 100644
--- a/src/main/ssh/ssh-system-no-input-windows-openssh.test.ts
+++ b/src/main/ssh/ssh-system-no-input-windows-openssh.test.ts
@@ -1,4 +1,5 @@
import { spawn } from 'node:child_process'
+import { join } from 'node:path'
import { performance } from 'node:perf_hooks'
import { describe, expect, it } from 'vitest'
@@ -26,9 +27,12 @@ type DiagnosticResult = {
const host = process.env.ORCA_SSH_RELAY_LIVE_WINDOWS_SYSTEM_SSH_HOST
const user = process.env.ORCA_SSH_RELAY_LIVE_WINDOWS_SYSTEM_SSH_USER
const identityFile = process.env.ORCA_SSH_RELAY_LIVE_WINDOWS_SYSTEM_SSH_IDENTITY
+const clientHome = process.env.ORCA_SSH_RELAY_LIVE_WINDOWS_SYSTEM_SSH_CLIENT_HOME
const launcherPath = process.env.ORCA_SSH_WINDOWS_NO_INPUT_LAUNCHER
const port = Number.parseInt(process.env.ORCA_SSH_RELAY_LIVE_WINDOWS_SYSTEM_SSH_PORT ?? '', 10)
-const hasLiveInput = Boolean(host && user && identityFile && launcherPath && Number.isInteger(port))
+const hasLiveInput = Boolean(
+ host && user && identityFile && clientHome && launcherPath && Number.isInteger(port)
+)
function createTarget(): SshTarget {
return {
@@ -44,6 +48,25 @@ function createTarget(): SshTarget {
}
}
+function buildDiagnosticSshArgs(target: SshTarget, knownHostsPath: string): string[] {
+ const sshArgs = buildSshArgs(target)
+ const destinationSeparator = sshArgs.indexOf('--')
+ if (destinationSeparator < 0) {
+ throw new Error('Windows OpenSSH diagnostic arguments lost the destination separator')
+ }
+ // Why: Win32-OpenSSH ignores overridden profile variables; use only the fixture's pinned trust.
+ sshArgs.splice(
+ destinationSeparator,
+ 0,
+ '-vvv',
+ '-o',
+ 'StrictHostKeyChecking=yes',
+ '-o',
+ `UserKnownHostsFile=${knownHostsPath}`
+ )
+ return sshArgs
+}
+
async function runDiagnostic(): Promise {
const sshPath = findSystemSsh()
if (!sshPath) {
@@ -51,14 +74,10 @@ async function runDiagnostic(): Promise {
}
const mode: DiagnosticMode = 'private-console-regular-output-verbose-timeout'
const startedAt = performance.now()
- // Why: Win32-OpenSSH still hangs with proven console EOF plus piped output, so this diagnostic
- // isolates stdout/stderr as bounded regular files without changing production transport.
- const sshArgs = buildSshArgs(createTarget())
- const destinationSeparator = sshArgs.indexOf('--')
- if (destinationSeparator < 0) {
- throw new Error('Windows OpenSSH diagnostic arguments lost the destination separator')
- }
- sshArgs.splice(destinationSeparator, 0, '-vvv')
+ const sshArgs = buildDiagnosticSshArgs(
+ createTarget(),
+ join(clientHome as string, '.ssh', 'known_hosts')
+ )
const child = spawn(
launcherPath as string,
['--diagnostic-timeout-ms', '6000', sshPath, ...sshArgs, 'echo ORCA-SYSTEM-SSH-OK'],
@@ -147,6 +166,42 @@ async function runDiagnostic(): Promise {
})
}
+describe('Windows OpenSSH no-input diagnostic trust arguments', () => {
+ it('adds only strict fixture trust and verbosity before the destination separator', () => {
+ const target: SshTarget = {
+ id: 'windows-no-input-contract',
+ label: 'windows-no-input-contract',
+ host: '127.0.0.1',
+ port: 22224,
+ username: 'fixture-user',
+ identityFile: 'C:\\fixture\\client-key',
+ identitiesOnly: true,
+ systemSshConnectionReuse: true,
+ source: 'manual'
+ }
+ const knownHostsPath = 'C:\\fixture\\client-home\\.ssh\\known_hosts'
+ const productionArgs = buildSshArgs(target)
+ const diagnosticArgs = buildDiagnosticSshArgs(target, knownHostsPath)
+ const destinationSeparator = productionArgs.indexOf('--')
+ const diagnosticOnlyArgs = [
+ '-vvv',
+ '-o',
+ 'StrictHostKeyChecking=yes',
+ '-o',
+ `UserKnownHostsFile=${knownHostsPath}`
+ ]
+
+ expect(diagnosticArgs).toEqual([
+ ...productionArgs.slice(0, destinationSeparator),
+ ...diagnosticOnlyArgs,
+ ...productionArgs.slice(destinationSeparator)
+ ])
+ expect(diagnosticArgs.indexOf('-vvv')).toBeLessThan(diagnosticArgs.indexOf('--'))
+ expect(diagnosticArgs).not.toContain('StrictHostKeyChecking=no')
+ expect(buildSshArgs(target)).toEqual(productionArgs)
+ })
+})
+
describe.skipIf(!hasLiveInput)('Windows OpenSSH no-input child-handle diagnostic', () => {
it(
'captures the verbose client phase after a bounded private-console diagnostic timeout',
|