diff --git a/.github/workflows/ssh-relay-runtime-artifacts.yml b/.github/workflows/ssh-relay-runtime-artifacts.yml
index 1c0b2b51349..731fe04f550 100644
--- a/.github/workflows/ssh-relay-runtime-artifacts.yml
+++ b/.github/workflows/ssh-relay-runtime-artifacts.yml
@@ -108,6 +108,7 @@ jobs:
config/scripts/ssh-relay-node-tar-inspection.test.mjs \
config/scripts/ssh-relay-node-zip-inspection.test.mjs \
config/scripts/ssh-relay-runtime-artifact.test.mjs \
+ config/scripts/ssh-relay-runtime-pty-smoke.test.mjs \
config/scripts/ssh-relay-runtime-windows-tree.test.mjs \
config/scripts/ssh-relay-runtime-zip.test.mjs \
config/scripts/ssh-relay-runtime-workflow.test.mjs
@@ -249,6 +250,7 @@ jobs:
config/scripts/ssh-relay-node-tar-inspection.test.mjs `
config/scripts/ssh-relay-node-zip-inspection.test.mjs `
config/scripts/ssh-relay-runtime-artifact.test.mjs `
+ config/scripts/ssh-relay-runtime-pty-smoke.test.mjs `
config/scripts/ssh-relay-runtime-windows-tree.test.mjs `
config/scripts/ssh-relay-runtime-zip.test.mjs `
config/scripts/ssh-relay-runtime-workflow.test.mjs
diff --git a/config/scripts/ssh-relay-runtime-pty-smoke.cjs b/config/scripts/ssh-relay-runtime-pty-smoke.cjs
new file mode 100644
index 00000000000..411e66242e7
--- /dev/null
+++ b/config/scripts/ssh-relay-runtime-pty-smoke.cjs
@@ -0,0 +1,127 @@
+'use strict'
+
+function deadline(label, timeoutMs) {
+ let timeout
+ const promise = new Promise((_, reject) => {
+ timeout = setTimeout(() => reject(new Error(`${label} exceeded ${timeoutMs} ms`)), timeoutMs)
+ })
+ return { promise, cancel: () => clearTimeout(timeout) }
+}
+
+async function runSshRelayRuntimePtySmoke({
+ nodePty,
+ runtimeRequire,
+ runtimeRoot,
+ platform = process.platform,
+ environment = process.env,
+ timeoutMs = 15_000
+}) {
+ const windows = platform === 'win32'
+ const executable = windows
+ ? 'powershell.exe'
+ : environment.SHELL && environment.SHELL.startsWith('/')
+ ? environment.SHELL
+ : '/bin/sh'
+ const arguments_ = windows
+ ? [
+ '-NoLogo',
+ '-NoProfile',
+ '-Command',
+ "$ErrorActionPreference='Stop';" +
+ '[Console]::OutputEncoding=[Text.UTF8Encoding]::new($false);' +
+ "Write-Output 'ORCA_PTY_READY';" +
+ '$line=[Console]::ReadLine();' +
+ '$size=$Host.UI.RawUI.WindowSize;' +
+ 'Write-Output ("ORCA_PTY_SIZE:{0}x{1}" -f $size.Width,$size.Height);' +
+ 'Write-Output ("ORCA_PTY_INPUT:{0}" -f $line);' +
+ 'exit 23'
+ ]
+ : [
+ '-c',
+ 'printf "ORCA_PTY_READY\\n"; IFS= read -r line; stty size; printf "ORCA_PTY_INPUT:%s\\n" "$line"; exit 23'
+ ]
+ const terminal = nodePty.spawn(executable, arguments_, {
+ name: 'xterm-256color',
+ cols: 80,
+ rows: 24,
+ cwd: runtimeRoot,
+ env: environment,
+ useConpty: windows,
+ // Why: the relay uses the bundled ConPTY runtime to preserve terminal rendering behavior.
+ useConptyDll: windows
+ })
+ let output = ''
+ let wroteInput = false
+ const outputSubscription = terminal.onData((data) => {
+ output += data
+ if (!wroteInput && output.includes('ORCA_PTY_READY')) {
+ wroteInput = true
+ terminal.resize(101, 37)
+ terminal.write('bounded-marker\r')
+ }
+ })
+ let exitSubscription
+ let limitSubscription
+ const exited = new Promise((resolve, reject) => {
+ exitSubscription = terminal.onExit(resolve)
+ limitSubscription = terminal.onData(() => {
+ if (output.length > 1024 * 1024) {
+ reject(new Error('PTY smoke output exceeded 1 MiB'))
+ }
+ })
+ })
+ const timer = deadline('PTY smoke', timeoutMs)
+ let result
+ let cleanupStarted = false
+ function settlePtyResources() {
+ if (cleanupStarted) {
+ return
+ }
+ cleanupStarted = true
+ try {
+ outputSubscription.dispose()
+ exitSubscription.dispose()
+ limitSubscription.dispose()
+ } finally {
+ if (!result || windows) {
+ // Why: node-pty retains its Windows ConPTY worker handles after process exit until kill().
+ terminal.kill()
+ }
+ }
+ }
+ try {
+ result = await Promise.race([exited, timer.promise])
+ if (
+ result.exitCode !== 23 ||
+ !output.includes('ORCA_PTY_INPUT:bounded-marker') ||
+ !output.includes(windows ? 'ORCA_PTY_SIZE:101x37' : '37 101')
+ ) {
+ throw new Error(
+ `PTY smoke mismatch: exit=${result.exitCode} output=${JSON.stringify(output)}`
+ )
+ }
+ const { loadNativeModule } = runtimeRequire('node-pty/lib/utils')
+ const nativeNames = windows ? ['conpty', 'conpty_console_list'] : ['pty']
+ const nativeDirectories = nativeNames.map((name) => loadNativeModule(name).dir)
+ if (
+ nativeDirectories.some(
+ (directory) => !directory.replaceAll('\\', '/').includes('build/Release/')
+ )
+ ) {
+ throw new Error(
+ `node-pty did not load patched build/Release artifacts: ${nativeDirectories.join(', ')}`
+ )
+ }
+ return {
+ exitCode: result.exitCode,
+ resizedRows: 37,
+ resizedColumns: 101,
+ nativeDirectory: nativeDirectories.join(', ')
+ }
+ } finally {
+ timer.cancel()
+ settlePtyResources()
+ }
+}
+
+module.exports = { runSshRelayRuntimePtySmoke }
diff --git a/config/scripts/ssh-relay-runtime-pty-smoke.test.mjs b/config/scripts/ssh-relay-runtime-pty-smoke.test.mjs
new file mode 100644
index 00000000000..bd0d375f14f
--- /dev/null
+++ b/config/scripts/ssh-relay-runtime-pty-smoke.test.mjs
@@ -0,0 +1,91 @@
+import { createRequire } from 'node:module'
+
+import { describe, expect, it, vi } from 'vitest'
+
+const require = createRequire(import.meta.url)
+const { runSshRelayRuntimePtySmoke } = require('./ssh-relay-runtime-pty-smoke.cjs')
+
+function successfulTerminalFixture({ windows }) {
+ const dataListeners = []
+ const exitListeners = []
+ const subscriptions = []
+ const terminal = {
+ kill: vi.fn(),
+ resize: vi.fn(),
+ write: vi.fn(),
+ onData: vi.fn((listener) => {
+ dataListeners.push(listener)
+ const subscription = { dispose: vi.fn() }
+ subscriptions.push(subscription)
+ return subscription
+ }),
+ onExit: vi.fn((listener) => {
+ exitListeners.push(listener)
+ const subscription = { dispose: vi.fn() }
+ subscriptions.push(subscription)
+ return subscription
+ })
+ }
+ const nodePty = {
+ spawn: vi.fn(() => {
+ queueMicrotask(() => {
+ const output = windows
+ ? 'ORCA_PTY_READY\r\nORCA_PTY_SIZE:101x37\r\nORCA_PTY_INPUT:bounded-marker\r\n'
+ : 'ORCA_PTY_READY\n37 101\nORCA_PTY_INPUT:bounded-marker\n'
+ dataListeners.forEach((listener) => listener(output))
+ exitListeners.forEach((listener) => listener({ exitCode: 23, signal: 0 }))
+ })
+ return terminal
+ })
+ }
+ return { nodePty, subscriptions, terminal }
+}
+
+function runtimeRequire() {
+ return {
+ loadNativeModule: () => ({ dir: '../build/Release/' })
+ }
+}
+
+describe('SSH relay runtime PTY smoke lifecycle', () => {
+ it('releases successful Windows ConPTY resources after validating the exit', async () => {
+ const fixture = successfulTerminalFixture({ windows: true })
+
+ await expect(
+ runSshRelayRuntimePtySmoke({
+ nodePty: fixture.nodePty,
+ runtimeRequire,
+ runtimeRoot: 'C:\\runtime',
+ platform: 'win32',
+ environment: {},
+ timeoutMs: 100
+ })
+ ).resolves.toMatchObject({ exitCode: 23, resizedColumns: 101, resizedRows: 37 })
+
+ expect(fixture.terminal.kill).toHaveBeenCalledOnce()
+ expect(fixture.subscriptions).toHaveLength(3)
+ fixture.subscriptions.forEach((subscription) => {
+ expect(subscription.dispose).toHaveBeenCalledOnce()
+ })
+ })
+
+ it('disposes successful POSIX listeners without killing an exited terminal', async () => {
+ const fixture = successfulTerminalFixture({ windows: false })
+
+ await expect(
+ runSshRelayRuntimePtySmoke({
+ nodePty: fixture.nodePty,
+ runtimeRequire,
+ runtimeRoot: '/runtime',
+ platform: 'linux',
+ environment: { SHELL: '/bin/sh' },
+ timeoutMs: 100
+ })
+ ).resolves.toMatchObject({ exitCode: 23, resizedColumns: 101, resizedRows: 37 })
+
+ expect(fixture.terminal.kill).not.toHaveBeenCalled()
+ fixture.subscriptions.forEach((subscription) => {
+ expect(subscription.dispose).toHaveBeenCalledOnce()
+ })
+ })
+})
diff --git a/config/scripts/ssh-relay-runtime-smoke-child.cjs b/config/scripts/ssh-relay-runtime-smoke-child.cjs
index 75e20e61415..b092b793905 100644
--- a/config/scripts/ssh-relay-runtime-smoke-child.cjs
+++ b/config/scripts/ssh-relay-runtime-smoke-child.cjs
@@ -5,6 +5,8 @@ const { tmpdir } = require('node:os')
const { join } = require('node:path')
const { createRequire } = require('node:module')
+const { runSshRelayRuntimePtySmoke } = require('./ssh-relay-runtime-pty-smoke.cjs')
+
const runtimeRoot = process.argv[2]
if (!runtimeRoot) {
throw new Error('runtime root argument is required')
@@ -22,96 +24,6 @@ function deadline(label) {
return { promise, cancel: () => clearTimeout(timeout) }
}
-async function ptySmoke() {
- const windows = process.platform === 'win32'
- const executable = windows
- ? 'powershell.exe'
- : process.env.SHELL && process.env.SHELL.startsWith('/')
- ? process.env.SHELL
- : '/bin/sh'
- const arguments_ = windows
- ? [
- '-NoLogo',
- '-NoProfile',
- '-Command',
- "$ErrorActionPreference='Stop';" +
- '[Console]::OutputEncoding=[Text.UTF8Encoding]::new($false);' +
- "Write-Output 'ORCA_PTY_READY';" +
- '$line=[Console]::ReadLine();' +
- '$size=$Host.UI.RawUI.WindowSize;' +
- 'Write-Output ("ORCA_PTY_SIZE:{0}x{1}" -f $size.Width,$size.Height);' +
- 'Write-Output ("ORCA_PTY_INPUT:{0}" -f $line);' +
- 'exit 23'
- ]
- : [
- '-c',
- 'printf "ORCA_PTY_READY\\n"; IFS= read -r line; stty size; printf "ORCA_PTY_INPUT:%s\\n" "$line"; exit 23'
- ]
- const terminal = nodePty.spawn(executable, arguments_, {
- name: 'xterm-256color',
- cols: 80,
- rows: 24,
- cwd: runtimeRoot,
- env: process.env,
- useConpty: windows,
- // Why: the relay uses the bundled ConPTY runtime to preserve terminal rendering behavior.
- useConptyDll: windows
- })
- let output = ''
- let wroteInput = false
- terminal.onData((data) => {
- output += data
- if (!wroteInput && output.includes('ORCA_PTY_READY')) {
- wroteInput = true
- terminal.resize(101, 37)
- terminal.write('bounded-marker\r')
- }
- })
- const exited = new Promise((resolve, reject) => {
- terminal.onExit(resolve)
- terminal.onData(() => {
- if (output.length > 1024 * 1024) {
- reject(new Error('PTY smoke output exceeded 1 MiB'))
- }
- })
- })
- const timer = deadline('PTY smoke')
- let result
- try {
- result = await Promise.race([exited, timer.promise])
- } finally {
- timer.cancel()
- if (!result) {
- terminal.kill()
- }
- }
- if (
- result.exitCode !== 23 ||
- !output.includes('ORCA_PTY_INPUT:bounded-marker') ||
- !output.includes(windows ? 'ORCA_PTY_SIZE:101x37' : '37 101')
- ) {
- throw new Error(`PTY smoke mismatch: exit=${result.exitCode} output=${JSON.stringify(output)}`)
- }
- const { loadNativeModule } = runtimeRequire('node-pty/lib/utils')
- const nativeNames = windows ? ['conpty', 'conpty_console_list'] : ['pty']
- const nativeDirectories = nativeNames.map((name) => loadNativeModule(name).dir)
- if (
- nativeDirectories.some(
- (directory) => !directory.replaceAll('\\', '/').includes('build/Release/')
- )
- ) {
- throw new Error(
- `node-pty did not load patched build/Release artifacts: ${nativeDirectories.join(', ')}`
- )
- }
- return {
- exitCode: result.exitCode,
- resizedRows: 37,
- resizedColumns: 101,
- nativeDirectory: nativeDirectories.join(', ')
- }
-}
-
async function waitFor(events, predicate, label) {
const timer = deadline(label)
try {
@@ -177,7 +89,10 @@ async function watcherSmoke() {
async function main() {
const started = process.hrtime.bigint()
- const [pty, watched] = await Promise.all([ptySmoke(), watcherSmoke()])
+ const [pty, watched] = await Promise.all([
+ runSshRelayRuntimePtySmoke({ nodePty, runtimeRequire, runtimeRoot }),
+ watcherSmoke()
+ ])
const durationMs = Number(process.hrtime.bigint() - started) / 1e6
process.stdout.write(
`${JSON.stringify({ nodeVersion: process.version, modulesAbi: process.versions.modules, pty, watcher: watched, durationMs, rssBytes: process.memoryUsage().rss })}\n`
diff --git a/config/scripts/ssh-relay-runtime-workflow.test.mjs b/config/scripts/ssh-relay-runtime-workflow.test.mjs
index 4ef61105223..53e3362df21 100644
--- a/config/scripts/ssh-relay-runtime-workflow.test.mjs
+++ b/config/scripts/ssh-relay-runtime-workflow.test.mjs
@@ -59,6 +59,7 @@ describe('SSH relay runtime artifact workflow', () => {
expect(source).toContain('cp "$output"/*.tar.xz')
expect(source).toContain("Get-ChildItem -LiteralPath $output -Filter '*.zip'")
expect(source).toContain('ssh-relay-node-zip-inspection.test.mjs')
+ expect(source).toContain('ssh-relay-runtime-pty-smoke.test.mjs')
expect(source).toContain('ssh-relay-runtime-zip.test.mjs')
expect(source).toContain('node-v24.18.0-headers.tar.gz')
expect(source).toContain('node_library: win-x64/node.lib')
diff --git a/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist.md b/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist.md
index 5be5d9a25cc..d83e11de41e 100644
--- a/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist.md
+++ b/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist.md
@@ -2,7 +2,7 @@
Date created: 2026-07-14
Last updated: 2026-07-14
-Current phase: Milestone 3 / Work Package 2 target-native runtime assembly — four POSIX native-runner artifact builds are CI-green; Windows signed-input verification and runtime/ZIP assembly reach native smoke on both architectures, but bounded smoke diagnostics/execution, reproducibility, oldest-baseline, native-trust, cross-family remote, and measured-baseline gates remain open; no bundled-runtime path is enabled
+Current phase: Milestone 3 / Work Package 2 target-native runtime assembly — correct prompt Windows PTY smoke-process settlement after functionally successful native x64 and arm64 execution; exact-head green CI, reproducibility, oldest-baseline, native-trust, cross-family remote, and measured-baseline gates remain open; no bundled-runtime path is enabled
Primary design: [SSH relay GitHub Release plan](./2026-07-14-ssh-relay-github-release-plan.html)
Motivating issues: [#8450](https://github.com/stablyai/orca/issues/8450), [#1693](https://github.com/stablyai/orca/issues/1693)
@@ -61,12 +61,15 @@ same change as the work it records.
smoke, SBOM, and provenance only. The Windows x64/arm64 artifact candidate and portability
corrections are implemented through `b6903b220`, with bounded smoke diagnostics in `3aab5aff8`,
in stacked draft PR
- [#8741](https://github.com/stablyai/orca/pull/8741). Both native architectures passed all seven
- contract suites, exact signed-input verification, native compilation, and bounded runtime/ZIP
- assembly at exact CI head `42aa02fa9` (E-M3-WINDOWS-CI-RED-004). Both then time out during the
- bundled smoke, while the parent currently suppresses bounded child stderr needed to classify the
- failing PTY or watcher substage. This package may produce test artifacts but must not publish,
- resolve, transfer, install, launch, or enable them.
+ [#8741](https://github.com/stablyai/orca/pull/8741). Exact-head run
+ [29341643555](https://github.com/stablyai/orca/actions/runs/29341643555) proves the bundled Node,
+ patched PTY input/resize/exit, and watcher lifecycle complete on x64 in 3,357.413 ms with
+ 56,905,728-byte RSS and arm64 in 6,593.663 ms with 54,505,472-byte RSS, but each child retains a
+ Windows handle until the parent kills it at its 45-second bound. The active slice is a
+ discriminating PTY-listener/terminal-cleanup contract followed by explicit prompt ConPTY
+ settlement; the injected lifecycle contract and repository static gates are locally green, while
+ exact-head native execution remains mandatory. This package may produce test artifacts but must
+ not publish, resolve, transfer, install, launch, or enable them.
- Active evidence gate: the immutable Node v24.18.0 contract, pinned release key, bounded verifier,
and artifact-only CLI are locally green under E-M3-NODE-RED-001 and E-M3-NODE-PROVENANCE-001.
E-M3-RUNTIME-LOCAL-001 additionally proves one unpublished Linux arm64 glibc assembly, exact-tree
@@ -578,6 +581,11 @@ archive inspection, bundled-Node/native-module/PTY/watcher smoke, SBOM, and prov
behind purpose-named scripts and CI artifacts. No release publication, desktop resolver, SSH
transfer, install, fallback, rollout setting, or tuple enablement belongs in this package.
+**Active sub-gate — 2026-07-14, Codex implementation owner:** the discriminating lifecycle test and
+explicit listener/ConPTY cleanup are locally green without `process.exit()` or a weakened 45-second
+bound. Exact-head native x64/arm64 CI must now prove normal child settlement and artifact retention;
+the prior common failure is run 29341643555/jobs 87114639412 and 87114639449.
+
Each runtime must contain only the executable closure required by the relay.
- [ ] Replace or extend `config/scripts/build-relay.mjs` without weakening its existing relay and
@@ -1231,6 +1239,7 @@ focused commands as their scripts/tests are introduced.
- [x] `node config/scripts/verify-ssh-relay-node-release-inputs.mjs --inputs-directory --archive linux-x64-glibc` (E-M3-NODE-PROVENANCE-001; metadata and archive verification only)
- [x] `pnpm exec vitest run --config config/vitest.config.ts config/scripts/ssh-relay-node-zip-inspection.test.mjs config/scripts/ssh-relay-runtime-zip.test.mjs` (E-M3-WINDOWS-ZIP-RED-001, E-M3-WINDOWS-INPUT-001; synthetic ZIP/input contracts only)
- [x] `pnpm exec vitest run --config config/vitest.config.ts config/scripts/ssh-relay-runtime-windows-tree.test.mjs` (E-M3-WINDOWS-LOCAL-002; structural Windows ConPTY closure only, no execution)
+- [x] `pnpm exec vitest run --config config/vitest.config.ts config/scripts/ssh-relay-runtime-pty-smoke.test.mjs` (E-M3-WINDOWS-SMOKE-SETTLEMENT-LOCAL-RED-001, E-M3-WINDOWS-SMOKE-SETTLEMENT-LOCAL-001; native evidence remains pending)
- [x] `node config/scripts/verify-ssh-relay-node-release-inputs.mjs --inputs-directory --archive win32-x64` (E-M3-WINDOWS-INPUT-001; signed real Node ZIP, headers, and import library; no Windows execution)
- [x] `node config/scripts/build-ssh-relay-runtime.mjs --tuple linux-arm64-glibc --inputs-directory --output-directory --source-date-epoch --git-commit ` (E-M3-RUNTIME-LOCAL-001; local native Linux arm64 only)
- [x] `node config/scripts/verify-ssh-relay-runtime.mjs --runtime-directory --identity --archive ` (E-M3-RUNTIME-LOCAL-001; local native Linux arm64 only)
@@ -2842,6 +2851,136 @@ or unexpected token`; the first logs did not identify a source location.
- Follow-up: rerun native Windows x64, capture the classified child tail, and make no execution-path
change until that evidence identifies the actual failure.
+### E-M3-WINDOWS-SMOKE-SETTLEMENT-CI-RED-001 — Native Windows smoke succeeds but does not settle
+
+- Date: 2026-07-14
+- Commit SHA / PR: exact workflow head `df661e370102b9b66c26f4c708e641abef0aa1ae`; draft PR
+ [#8741](https://github.com/stablyai/orca/pull/8741)
+- Runners and jobs: GitHub Actions run
+ [29341643555](https://github.com/stablyai/orca/actions/runs/29341643555); Windows x64 job
+ [87114639412](https://github.com/stablyai/orca/actions/runs/29341643555/job/87114639412),
+ `windows-2022` image `20260706.237.1`, Windows Server 2022 10.0.20348, native x64, Node
+ v24.18.0; Windows arm64 job
+ [87114639449](https://github.com/stablyai/orca/actions/runs/29341643555/job/87114639449),
+ `windows-11-arm64` image `20260706.102.1`, Windows 11 Enterprise 10.0.26200, native arm64,
+ Node v24.18.0
+- Remote and transport: no SSH remote; target-native artifact build and bundled-runtime execution
+ on the hosted runner; exact signed inputs downloaded from pinned nodejs.org URLs
+- Exact command:
+
+ ```sh
+ gh api repos/stablyai/orca/actions/jobs/87114639412/logs | \
+ rg -n -C 16 'Bundled runtime smoke command failed|timeoutMs=|Image:|Version:'
+ gh api repos/stablyai/orca/actions/jobs/87114639449/logs | \
+ rg -n -C 16 'Bundled runtime smoke command failed|timeoutMs=|Image:|Version:'
+ ```
+
+- Result: expected discriminating FAIL. The exact signed inputs, offline native build, archive and
+ complete-tree verification all passed. Bundled Node v24.18.0/ABI 137 then completed the patched
+ ConPTY smoke with exit 23, 101×37 resize, input marker, and both native modules loaded from
+ `build/Release`; watcher create, update, rename-as-delete/create, and delete also completed. The
+ x64 child emitted valid JSON after 3,357.413 ms with 56,905,728-byte RSS; arm64 emitted the same
+ functional result after 6,593.663 ms with 54,505,472-byte RSS. Both remained alive until the
+ parent killed them at 45 seconds (`code=null`, `killed=true`, `signal="SIGTERM"`, empty stderr).
+- Artifact metrics: x64 content ID
+ `sha256:8cf9eb4e04459e25d710a28235a57e777d39f65168841c2408ab658243a21d94`; ZIP
+ 37,212,068 bytes with SHA-256
+ `sha256:11f83971ed20cde7be41aa2f753cfd4350cd4a70a3fe46a27540ebc872c4ca56`; build
+ 151,226.208 ms. Arm64 content ID
+ `sha256:dda60b6237b320c74236f57bece072d0f847479eb322f43f22c829daf2ce9bf6`; ZIP
+ 33,261,533 bytes with SHA-256
+ `sha256:f3fefed7b959fb6c3945170e8f0f7d2766cf26240aef9928b0e25770e5b19a26`; 86,189,740
+ expanded bytes; build 248,307.259 ms. Uploads remained skipped because prompt process settlement
+ is part of executable proof.
+- Oracle proved: Windows x64 and arm64 PTY/ConPTY and watcher functionality succeeds through each
+ exact bundled runtime, and the common remaining failure occurs after successful JSON emission in
+ child-process handle settlement rather than in PTY, watcher, archive, or tree validation.
+- Does not prove: prompt cleanup, durable artifact upload, clean-rebuild identity, native
+ trust/signing, oldest baseline, SSH, or any enabled tuple. Both per-tuple rows remain unchecked
+ until the child exits normally and exact-head CI retains each artifact.
+- Follow-up: retain and dispose the PTY listener subscriptions, call the supported Windows terminal
+ cleanup after a validated successful exit, and prove normal child settlement without
+ `process.exit()` on both native architectures.
+
+### E-M3-WINDOWS-SMOKE-SETTLEMENT-LOCAL-RED-001 — PTY lifecycle cleanup contract red gate
+
+- Date: 2026-07-14
+- Commit SHA / PR: uncommitted contract test and behavior-preserving PTY-smoke module extraction on
+ exact base `df661e370102b9b66c26f4c708e641abef0aa1ae`; draft PR
+ [#8741](https://github.com/stablyai/orca/pull/8741)
+- Runner: macOS 26.2 arm64; Node v26.0.0 and pnpm 10.24.0
+- Remote and transport: none; injected terminal/listener lifecycle only
+- Exact command:
+ `pnpm exec vitest run --config config/vitest.config.ts config/scripts/ssh-relay-runtime-pty-smoke.test.mjs`
+- Result: expected FAIL in 122 ms. The Windows success case returned a valid exit result but called
+ `terminal.kill()` zero times; the POSIX success case and Windows case both disposed zero of their
+ three `onData`/`onExit` subscriptions. Two tests failed, with no timeout or synthetic forced exit.
+- Oracle proved: the current success path lacks the exact listener and ConPTY cleanup operations
+ required by the native x64 diagnostic, and the purpose-named suite distinguishes Windows-only
+ terminal cleanup from platform-neutral listener disposal.
+- Does not prove: the green implementation, actual Windows handle release, timeout/error cleanup,
+ full child-process settlement, arm64 behavior, or any tuple support.
+- Checklist items satisfied: red half of the Windows PTY smoke-settlement correction only.
+- Follow-up: add idempotent finally cleanup, preserve successful POSIX no-kill behavior, rerun this
+ suite and all artifact/static gates, then require exact-head native Windows CI.
+
+### E-M3-WINDOWS-SMOKE-SETTLEMENT-LOCAL-001 — Explicit PTY resource settlement
+
+- Date: 2026-07-14
+- Commit SHA / PR: uncommitted implementation on exact base
+ `df661e370102b9b66c26f4c708e641abef0aa1ae`; draft PR
+ [#8741](https://github.com/stablyai/orca/pull/8741)
+- Runner: macOS 26.2 arm64; Node v26.0.0 and pnpm 10.24.0. Exact-head Node 24 native CI remains
+ authoritative.
+- Remote and transport: none; injected terminal lifecycle plus local source/static verification
+- Exact commands:
+
+ ```sh
+ pnpm exec vitest run --config config/vitest.config.ts \
+ config/scripts/ssh-relay-runtime-pty-smoke.test.mjs
+ pnpm exec vitest run --config config/vitest.config.ts \
+ config/scripts/ssh-relay-node-release-verification.test.mjs \
+ config/scripts/ssh-relay-node-tar-inspection.test.mjs \
+ config/scripts/ssh-relay-node-zip-inspection.test.mjs \
+ config/scripts/ssh-relay-runtime-artifact.test.mjs \
+ config/scripts/ssh-relay-runtime-pty-smoke.test.mjs \
+ config/scripts/ssh-relay-runtime-windows-tree.test.mjs \
+ config/scripts/ssh-relay-runtime-zip.test.mjs \
+ config/scripts/ssh-relay-runtime-workflow.test.mjs
+ pnpm run typecheck
+ pnpm exec oxlint \
+ config/scripts/ssh-relay-runtime-smoke-child.cjs \
+ config/scripts/ssh-relay-runtime-pty-smoke.cjs \
+ config/scripts/ssh-relay-runtime-pty-smoke.test.mjs \
+ config/scripts/ssh-relay-runtime-workflow.test.mjs
+ pnpm run check:max-lines-ratchet
+ GOMAXPROCS=2 pnpm run lint
+ pnpm exec oxfmt --check .github/workflows/ssh-relay-runtime-artifacts.yml \
+ config/scripts/ssh-relay-runtime-smoke-child.cjs \
+ config/scripts/ssh-relay-runtime-pty-smoke.cjs \
+ config/scripts/ssh-relay-runtime-pty-smoke.test.mjs \
+ config/scripts/ssh-relay-runtime-workflow.test.mjs \
+ docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist.md
+ git diff --check
+ ```
+
+- Result: PASS. The lifecycle suite passed 2/2 tests in 117 ms; the eight artifact suites passed
+ 25/25 tests in 417 ms. Typecheck, focused oxlint, max-lines ratchet, full
+ lint/reliability/localization checks, formatting, and diff whitespace passed. Full lint reported
+ only pre-existing warnings outside this package.
+- Oracle proved: the success path retains and disposes both data subscriptions and the exit
+ subscription exactly once; a validated Windows exit additionally calls the supported node-pty
+ terminal cleanup exactly once, while a successful POSIX exit does not kill its terminal. Cleanup
+ is in `finally`, the existing timeout/error path still kills the terminal, and no `process.exit()`
+ was introduced. Both native workflow families now run the lifecycle contract.
+- Does not prove: actual Windows ConPTY handle release, prompt bundled child-process exit, exact-head
+ Node 24 behavior, artifact retention, clean-rebuild identity, native trust, oldest baseline, SSH,
+ or any enabled tuple. Both Windows per-tuple cells remain unchecked.
+- Checklist items satisfied: local green half of the PTY smoke-settlement correction and its
+ purpose-named verification-command inventory only.
+- Follow-up: commit and push the isolated correction, run both target-native Windows jobs at the
+ exact head, and require normal smoke completion plus artifact upload before advancing.
+
### E-M3-RUNTIME-LOCAL-001 — First target-native Linux arm64 runtime artifact
- Date: 2026-07-14
@@ -3081,7 +3220,7 @@ owner and promotion condition.
| ------------------------------------------ | ----------------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------ |
| Bundled runtime only partially implemented | Four unpublished POSIX native artifact proofs; no production consumer | #8450/#1693 environment failures remain | Codex implementation owner | Complete Work Packages 2–7 plus Milestones 3–14 | Open |
| No bundled tuple enabled | Every target's default and effective mode remains legacy | No bundled support claim can be made | Codex implementation owner | Complete target-native build/trust and both required live-evidence layers | Open |
-| Windows runtime smoke incomplete | Native candidate ZIPs build, but smoke fails before artifact retention | Pre-smoke proof cannot establish relay behavior | Codex implementation owner | Classified passing PTY/watcher smoke, reproducibility, trust, and live gates | Open |
+| Windows runtime smoke incomplete | Both native smokes work but prior children hung; local cleanup awaits CI | No prompt settlement or retained artifact proof | Codex implementation owner | Exact-head clean exit/upload, reproducibility, trust, and live gates | Open |
| Native clean-rebuild identity unproved | One successful artifact per corrected-head hosted runner | Toolchain drift may change native content IDs | Codex implementation owner | Same-head, same-runner clean builds match or a reviewed reproducibility policy | Open |
| Cross-family Layer B remotes unavailable | GitHub native runner labels exist; no approved reachable target pool | Client/remote integration gaps may escape | Repository release administrator + implementation owner | Approve provider/snapshots/credentials/egress/teardown/cost owner | BLOCKED |
| Musl has no accepted official Node binary | Musl is deliberately legacy-only | Unofficial binary would break provenance trust | Codex implementation owner | Orca-owned target-native source build, signing, provenance, and live gates | ACCEPTED GAP |
@@ -3129,9 +3268,10 @@ The project is not complete until every applicable item below is checked with ev
## Next Required Action
-Implement bounded deterministic Windows ZIP/native assembly as its own evidence-gated slice, add
-native Windows x64/arm64 jobs without publishing assets, and add a same-head/same-runner clean-build
-identity comparison for native reproducibility. The cross-family Layer B target pool, protected
-manifest-signing environment, and paired legacy performance baseline remain release/default-path
-blockers; no publication, desktop resolver, SSH transfer/install, per-target Beta, fallback, tuple
-enablement, or default behavior may be connected by this package.
+Commit and push the isolated PTY smoke-settlement correction, then require exact-head Windows
+x64/arm64 jobs to exit normally and upload their unpublished evidence artifacts. If both pass, record
+their exact hashes, sizes, smoke/build durations, RSS, runner images, and residual gaps before the
+separate same-head/same-runner clean-build identity gate. The cross-family Layer B target pool,
+protected manifest-signing environment, and paired legacy performance baseline remain
+release/default-path blockers; no publication, desktop resolver, SSH transfer/install, per-target
+Beta, fallback, tuple enablement, or default behavior may be connected by this package.