fix(ssh): match Windows runtime pipe buffers

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-07-17 04:20:41 -04:00
co-authored by Orca
parent c93111a14b
commit d7fcdb2597
5 changed files with 67 additions and 27 deletions
@@ -9,16 +9,16 @@ keeps commands, hashes, runner identities, timings, and failure details.
A checked box means the work has evidence in the detailed ledger. Design approval alone does not
complete a box.
Active checkpoint: **Milestone 6 / Work Package 5 bounded runtime transfer — Windows borrowed-chunk
pipe-write correction locally green, exact-head native qualification next, 2026-07-17, Codex
implementation owner.** Exact diagnostic head
`ce4c7c481c790eacbf73162e5e03570fc2d3b490`, run `29563868935`, and Windows x64/ARM64 jobs
`87832001707`/`87832001736` independently complete the 18-byte first file and stall before accepting
any bytes of `THIRD_PARTY_LICENSES.txt`. The isolated correction uses sequential zero-copy 16 KiB
Windows pipe views while retaining the borrowed source buffer until all subwrites settle. Focused,
broad, release, typecheck, lint/reliability/max-lines, formatting, diff, and resolver isolation are
green. Commit/push only this package for fresh native proof. No product/default caller, Beta,
fallback, tuple, publication, or signing behavior is authorized.
Active checkpoint: **Milestone 6 / Work Package 5 bounded runtime transfer — matched 4 KiB Windows
pipe correction locally green, native qualification next, 2026-07-17, Codex implementation
owner.** Exact head
`c93111a14bdb5390f99aa44a9004449625cbdcb5`, run `29564980476`, and x64/ARM64 jobs
`87835460661`/`87835460642` falsify client-only 16 KiB subdivision: x64 stalls after the 18-byte
first file, while ARM64 completes the 180,827-byte license and stalls on `node.exe`. Client pipe
writes and remote .NET reads now match at 4 KiB while preserving the source 64 KiB buffer; focused,
broad, release, typecheck, lint/reliability/max-lines, formatting, diff, and resolver isolation pass.
Commit/push only this package. No product/default caller, Beta, fallback, tuple, publication, or
signing behavior is authorized.
`E-M6-WINDOWS-SYSTEM-SSH-TREE-LIVE-PORTABLE-FIXTURE-LOCAL-001` records the portable-fixture
correction locally green: the no-Orca-publication workflow oracle permits the one exact pinned
Microsoft fixture release URL while Orca release URLs, `gh release`, and `contents: write` remain
@@ -8,8 +8,8 @@ work; keep exact commands, runner identities, hashes, metrics, and residual gaps
Date created: 2026-07-14<br>
Last updated: 2026-07-17<br>
Current phase: Milestone 6 / Work Package 5 bounded runtime transfer — **In progress — Windows borrowed-chunk pipe-write correction locally green, exact-head native qualification next, 2026-07-17, Codex implementation owner**. Exact diagnostic head `ce4c7c481c790eacbf73162e5e03570fc2d3b490`, run `29563868935`, and Windows x64/ARM64 jobs `87832001707`/`87832001736` independently prove the first borrowed 64 KiB payload write stalls. `E-M6-WINDOWS-PIPE-SUBWRITE-LOCAL-001` subdivides only that Windows destination write into sequential zero-copy 16 KiB views while retaining the source buffer until every subwrite settles. Commit/push only this correction and require fresh native proof. Legacy remains the sole production path; real Apple/SignPath rehearsals remain deferred.<br>
Session checkpoint: **WINDOWS 16 KIB PIPE SUBWRITE LOCAL GREEN / NATIVE RUN NEXT — 2026-07-17, Codex implementation owner** — 55 focused cases with three declared skips, 698 broad relay cases with ten declared skips, 285 release contracts with eight declared skips, typecheck, targeted/full lint, reliability/max-lines, formatting, diff, and resolver isolation pass. The remote 64 KiB .NET buffer, source 64 KiB worker buffer, every other transfer family, and all product/default behavior remain unchanged.<br>
Current phase: Milestone 6 / Work Package 5 bounded runtime transfer — **In progress — matched 4 KiB Windows pipe correction locally green, native qualification next, 2026-07-17, Codex implementation owner**. Exact head `c93111a14bdb5390f99aa44a9004449625cbdcb5`, run `29564980476`, and Windows x64/ARM64 jobs `87835460661`/`87835460642` falsify client-only subdivision. `E-M6-WINDOWS-MATCHED-PIPE-LOCAL-001` matches client writes and remote .NET reads at 4 KiB while preserving the source 64 KiB buffer. Commit/push only this correction and require fresh native proof. Legacy remains the sole production path; real Apple/SignPath rehearsals remain deferred.<br>
Session checkpoint: **MATCHED 4 KIB PIPE LOCAL GREEN / NATIVE RUN NEXT — 2026-07-17, Codex implementation owner** — focused, broad relay, release-contract, typecheck, full lint/reliability/max-lines, formatting, diff, and resolver isolation pass. No product caller, default/fallback, Beta, tuple publication, or signing behavior changed.<br>
Primary design: [SSH relay GitHub Release plan](./2026-07-14-ssh-relay-github-release-plan.html)<br>
Motivating issues: [#8450](https://github.com/stablyai/orca/issues/8450), [#1693](https://github.com/stablyai/orca/issues/1693)
@@ -20555,6 +20555,41 @@ src/main/ssh/ssh-relay-runtime-windows-system-ssh-openssh-full-size.test.ts` exi
byte/tree validation, connection reuse, and exact fixture profile/directory teardown before
advancing.
### E-M6-WINDOWS-PIPE-SUBWRITE-CI-RED-001 — client-only subdivision is insufficient
- Date/source/run: 2026-07-17; exact head `c93111a14bdb5390f99aa44a9004449625cbdcb5`, run
[29564980476](https://github.com/stablyai/orca/actions/runs/29564980476), x64 job
[87835460661](https://github.com/stablyai/orca/actions/runs/29564980476/job/87835460661), and
ARM64 job [87835460642](https://github.com/stablyai/orca/actions/runs/29564980476/job/87835460642).
- Exact RED: x64 completes only the 18-byte `.version` file before the 60-second watchdog and retains
`THIRD_PARTY_LICENSES.txt`. ARM64 completes `.version` plus the 180,827-byte license file, then
stalls and retains `bin/node.exe` at 180,845 aggregate bytes. Tests finish in 72,580/77,910 ms;
both profile teardowns correctly expose retained fixture processes and locked `UsrClass.dat`.
- Classification/correction: architecture-variable progress falsifies client-only 16 KiB subdivision
and file-specific failure. Match Windows pipe writes and PowerShell/.NET reads at a conservative
4,096-byte quantum, keep the source worker's 65,536-byte reusable buffer and zero-copy borrowed
views, and require fresh two-architecture full-size metrics and clean teardown. The HTML plan and
both Markdown checklists are updated before code.
### E-M6-WINDOWS-MATCHED-PIPE-LOCAL-001 — matched 4 KiB Windows pipe quantum is locally green
- Date/base/runner: 2026-07-17; uncommitted correction atop exact RED head
`c93111a14bdb5390f99aa44a9004449625cbdcb5` on Apple arm64, macOS 26.2, Node 26.5.0, pnpm
10.24.0. Native Node 24 jobs remain authoritative.
- Boundary: client zero-copy subwrites and PowerShell/.NET reads are both capped at 4,096 bytes; the
source worker still owns one 65,536-byte buffer and releases it only after every subwrite callback.
Framing, size/tree verification, cancellation, POSIX/SFTP, SSH behavior, and product/default paths
are unchanged.
- Evidence: focused Windows tests pass 55 runnable cases with three skips in 3.31 seconds real
(141,262,848-byte max RSS). Broad relay passes 698 cases with ten skips in 34.40 seconds real
(306,413,568-byte max RSS). Release contracts pass 285 cases with eight skips in 28.62 seconds;
typecheck passes in 4.30 seconds; full lint passes with the existing 26 warnings, 41 reliability
gates, and 355-entry max-lines ratchet in 26.32 seconds. Formatting, diff, and resolver isolation
pass. The initial focused run failed only because its expected write count still encoded 16 KiB;
the limit-derived oracle is green.
- Residual: local Darwin skips native OpenSSH/PowerShell. Fresh x64/ARM64 full-size metrics and exact
teardown remain mandatory.
## Accepted Gaps
No product gap is accepted merely because it appears in this list. Each entry requires explicit
@@ -20613,8 +20648,8 @@ The project is not complete until every applicable item below is checked with ev
## Next Required Action
Commit and push only the Windows pipe-subwrite correction recorded by
`E-M6-WINDOWS-PIPE-SUBWRITE-LOCAL-001`, then require exact-head Windows x64/ARM64 full-size
Commit and push only the matched 4 KiB Windows pipe correction recorded by
`E-M6-WINDOWS-MATCHED-PIPE-LOCAL-001`, then require exact-head Windows x64/ARM64 full-size
serial/concurrent/collision/cancellation metrics, bounded memory, connection reuse, and exact
profile/directory teardown evidence. Do not check the broad Milestone 6 Windows system-SSH item or
add an Electron/startup/product importer, per-target mode wiring, fallback, tuple enablement, release
@@ -1004,12 +1004,14 @@
Windows uses a bounded binary PowerShell/.NET path and must not materialize the
runtime as one JSON/base64 buffer. The client may subdivide each borrowed 64 KiB
source chunk into smaller awaited Windows pipe writes, but must not release or
reuse that source buffer until every subwrite settles; the receiver retains its
fixed 64 KiB .NET buffer. SFTP uses bounded concurrency. After locally verifying
signed metadata and archive/tree hashes, transfer through authenticated SSH,
restore every declared executable bit, then execute the transferred bundled Node
to hash the entire staging tree. Verify the full tree, run bundled
Node/native-module and minimal PTY/watcher probes, write a structured
reuse that source buffer until every subwrite settles. Windows pipe writes and
.NET reads use the same conservative 4 KiB quantum to avoid platform pipe
backpressure cycles; the source worker retains its fixed 64 KiB buffer. SFTP uses
bounded concurrency. After locally verifying signed metadata and archive/tree
hashes, transfer through authenticated SSH, restore every declared executable bit,
then execute the transferred bundled Node to hash the entire staging tree. Verify
the full tree, run bundled Node/native-module and minimal PTY/watcher probes,
write a structured
<code>.install-complete</code> containing schema, mode, and digest, atomically
publish the immutable install, and only then launch. Preserve current locks,
reconnect, and garbage collection.
@@ -90,7 +90,7 @@ describe('SSH relay runtime Windows system-SSH file destination', () => {
expect(script).toContain('[Console]::OpenStandardInput()')
expect(script).toContain('[IO.FileMode]::CreateNew')
expect(script).toContain('[IO.FileShare]::None')
expect(script).toContain('New-Object byte[] 65536')
expect(script).toContain('New-Object byte[] 4096')
expect(script).toContain("-ne 'ORCAEND1'")
expect(script).not.toContain('$inputStream.ReadByte()')
for (const forbidden of ['ReadToEnd', 'CopyTo(', 'FromBase64String', 'ConvertFrom-Json']) {
@@ -113,8 +113,11 @@ describe('SSH relay runtime Windows system-SSH file destination', () => {
const destination = await opening
await destination.write(Buffer.alloc(65_537, 7))
const closing = destination.close()
await vi.waitFor(() => expect(channel.write).toHaveBeenCalledTimes(7))
expect(channel.write.mock.calls[6]?.[0]).toEqual(completionFrame)
const expectedWrites =
Math.ceil(65_537 / SSH_RELAY_RUNTIME_WINDOWS_FILE_DESTINATION_LIMITS.maximumPipeWriteBytes) +
2
await vi.waitFor(() => expect(channel.write).toHaveBeenCalledTimes(expectedWrites))
expect(channel.write.mock.calls.at(-1)?.[0]).toEqual(completionFrame)
resolve()
await closing
})
@@ -17,8 +17,8 @@ const HEADER_MAGIC = Buffer.from('ORCARLY1', 'ascii')
const COMPLETION_MAGIC = Buffer.from('ORCAEND1', 'ascii')
const FIXED_HEADER_BYTES = 20
const MAXIMUM_PATH_BYTES = 32 * 1024
const PAYLOAD_BUFFER_BYTES = 64 * 1024
const MAXIMUM_PIPE_WRITE_BYTES = 16 * 1024
const PAYLOAD_BUFFER_BYTES = 4 * 1024
const MAXIMUM_PIPE_WRITE_BYTES = PAYLOAD_BUFFER_BYTES
export const SSH_RELAY_RUNTIME_WINDOWS_FILE_DESTINATION_LIMITS = Object.freeze({
maximumHeaderBytes: FIXED_HEADER_BYTES + MAXIMUM_PATH_BYTES,
@@ -181,8 +181,8 @@ export async function openSshRelayRuntimeWindowsFileDestination(
if (payloadBytes + chunk.length > options.expectedSize) {
return abortForSizeMismatch()
}
// Why: native Win32-OpenSSH stalls on one borrowed 64 KiB pipe write; awaited subviews keep
// the source buffer borrowed until every byte has crossed the same retention boundary.
// Why: matched 4 KiB reads/writes avoid Win32 pipe backpressure cycles while zero-copy
// subviews keep the source's 64 KiB buffer borrowed until every byte settles.
for (let offset = 0; offset < chunk.length; offset += MAXIMUM_PIPE_WRITE_BYTES) {
await destination.write(chunk.subarray(offset, offset + MAXIMUM_PIPE_WRITE_BYTES))
}