diff --git a/.github/workflows/ssh-relay-runtime-artifacts.yml b/.github/workflows/ssh-relay-runtime-artifacts.yml
index 05f9979d6c8..f58cadb26c0 100644
--- a/.github/workflows/ssh-relay-runtime-artifacts.yml
+++ b/.github/workflows/ssh-relay-runtime-artifacts.yml
@@ -166,6 +166,8 @@ jobs:
node --check config/scripts/ssh-relay-runtime-manifest-assembly.test.mjs
node --check config/scripts/ssh-relay-runtime-manifest-signing-handoff.mjs
node --check config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs
+ node --check config/scripts/ssh-relay-runtime-manifest-seed-signing.mjs
+ node --check config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs
node --check config/scripts/ssh-relay-runtime-manifest-aggregate.mjs
node --check config/scripts/ssh-relay-runtime-manifest-aggregate.test.mjs
node --check config/scripts/ssh-relay-runtime-manifest-tuple.mjs
@@ -212,6 +214,7 @@ jobs:
config/scripts/ssh-relay-runtime-draft-readback.test.mjs \
config/scripts/ssh-relay-runtime-manifest-assembly.test.mjs \
config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs \
+ config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs \
config/scripts/ssh-relay-runtime-manifest-aggregate.test.mjs \
config/scripts/ssh-relay-runtime-manifest-tuple.test.mjs \
config/scripts/ssh-relay-runtime-post-sign-metadata.test.mjs \
@@ -578,6 +581,10 @@ jobs:
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest signing handoff syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest signing handoff test syntax check failed' }
+ node --check config/scripts/ssh-relay-runtime-manifest-seed-signing.mjs
+ if ($LASTEXITCODE -ne 0) { throw 'runtime manifest seed signing syntax check failed' }
+ node --check config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs
+ if ($LASTEXITCODE -ne 0) { throw 'runtime manifest seed signing test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-aggregate.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest aggregate syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-aggregate.test.mjs
@@ -642,6 +649,7 @@ jobs:
config/scripts/ssh-relay-runtime-draft-readback.test.mjs `
config/scripts/ssh-relay-runtime-manifest-assembly.test.mjs `
config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs `
+ config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs `
config/scripts/ssh-relay-runtime-manifest-aggregate.test.mjs `
config/scripts/ssh-relay-runtime-manifest-tuple.test.mjs `
config/scripts/ssh-relay-runtime-post-sign-metadata.test.mjs `
diff --git a/config/scripts/ssh-relay-runtime-manifest-seed-signing.mjs b/config/scripts/ssh-relay-runtime-manifest-seed-signing.mjs
new file mode 100644
index 00000000000..90ee70660e6
--- /dev/null
+++ b/config/scripts/ssh-relay-runtime-manifest-seed-signing.mjs
@@ -0,0 +1,236 @@
+import { lstat, mkdir, readFile, realpath, rm, writeFile } from 'node:fs/promises'
+import { basename, dirname, resolve } from 'node:path'
+import { pathToFileURL } from 'node:url'
+
+import nacl from 'tweetnacl'
+
+import {
+ createSshRelayRuntimeManifestSigningRequest,
+ sshRelayRuntimeManifestKeyId
+} from './ssh-relay-runtime-manifest-signing-handoff.mjs'
+
+const REQUEST_FIELDS = [
+ 'algorithm',
+ 'payloadBase64',
+ 'payloadSha256',
+ 'payloadSize',
+ 'schemaVersion'
+]
+const MAX_REQUEST_ARTIFACT_BYTES = 48 * 1024 * 1024
+const BASE64_PATTERN = /^[A-Za-z0-9+/]+={0,2}$/u
+
+function assertObject(value, label) {
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
+ throw new Error(`SSH relay runtime manifest seed signing ${label} must be an object`)
+ }
+}
+
+function assertExactFields(value, fields, label) {
+ assertObject(value, label)
+ const actual = Object.keys(value).sort()
+ const expected = [...fields].sort()
+ if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
+ throw new Error(
+ `SSH relay runtime manifest seed signing ${label} has unexpected or missing fields`
+ )
+ }
+}
+
+function decodeCanonicalBase64(value, label) {
+ if (typeof value !== 'string' || !BASE64_PATTERN.test(value)) {
+ throw new Error(`SSH relay runtime manifest seed signing ${label} is not canonical base64`)
+ }
+ const bytes = Buffer.from(value, 'base64')
+ if (bytes.length === 0 || bytes.toString('base64') !== value) {
+ throw new Error(`SSH relay runtime manifest seed signing ${label} is not canonical base64`)
+ }
+ return bytes
+}
+
+function validateInMemoryRequest(request) {
+ assertExactFields(
+ request,
+ ['algorithm', 'canonicalBytes', 'payloadSha256', 'payloadSize'],
+ 'request'
+ )
+ if (!Buffer.isBuffer(request.canonicalBytes) && !(request.canonicalBytes instanceof Uint8Array)) {
+ throw new Error('SSH relay runtime manifest seed signing request payload must be bytes')
+ }
+ const expected = createSshRelayRuntimeManifestSigningRequest(request.canonicalBytes)
+ if (
+ request.algorithm !== expected.algorithm ||
+ request.payloadSha256 !== expected.payloadSha256 ||
+ request.payloadSize !== expected.payloadSize
+ ) {
+ throw new Error('SSH relay runtime manifest seed signing request binding is inconsistent')
+ }
+ return expected
+}
+
+export function encodeSshRelayRuntimeManifestSigningRequestArtifact(request) {
+ const parsed = validateInMemoryRequest(request)
+ return {
+ schemaVersion: 1,
+ algorithm: parsed.algorithm,
+ payloadBase64: parsed.canonicalBytes.toString('base64'),
+ payloadSha256: parsed.payloadSha256,
+ payloadSize: parsed.payloadSize
+ }
+}
+
+export function decodeSshRelayRuntimeManifestSigningRequestArtifact(artifact) {
+ assertExactFields(artifact, REQUEST_FIELDS, 'request artifact')
+ if (artifact.schemaVersion !== 1 || artifact.algorithm !== 'ed25519-v1') {
+ throw new Error(
+ 'SSH relay runtime manifest seed signing request artifact schema is unsupported'
+ )
+ }
+ const canonicalBytes = decodeCanonicalBase64(artifact.payloadBase64, 'request payload')
+ const request = createSshRelayRuntimeManifestSigningRequest(canonicalBytes)
+ if (
+ artifact.payloadSize !== request.payloadSize ||
+ artifact.payloadSha256 !== request.payloadSha256
+ ) {
+ throw new Error(
+ 'SSH relay runtime manifest seed signing request artifact binding is inconsistent'
+ )
+ }
+ return request
+}
+
+function decodeSeed(seedBase64) {
+ const seed = decodeCanonicalBase64(seedBase64, 'seed')
+ if (seed.length !== nacl.sign.seedLength) {
+ throw new Error('SSH relay runtime manifest signing seed must contain exactly 32 bytes')
+ }
+ return seed
+}
+
+export function signSshRelayRuntimeManifestRequest({ requestArtifact, seedBase64 }) {
+ const request = decodeSshRelayRuntimeManifestSigningRequestArtifact(requestArtifact)
+ const pair = nacl.sign.keyPair.fromSeed(decodeSeed(seedBase64))
+ return {
+ keyId: sshRelayRuntimeManifestKeyId(pair.publicKey),
+ signature: Buffer.from(nacl.sign.detached(request.canonicalBytes, pair.secretKey)).toString(
+ 'base64'
+ )
+ }
+}
+
+export async function readSshRelayRuntimeManifestSigningRequestArtifact(path) {
+ const metadata = await lstat(path)
+ if (
+ !metadata.isFile() ||
+ metadata.isSymbolicLink() ||
+ metadata.size <= 0 ||
+ metadata.size > MAX_REQUEST_ARTIFACT_BYTES
+ ) {
+ throw new Error('SSH relay runtime manifest signing request must be a bounded regular file')
+ }
+ let artifact
+ try {
+ artifact = JSON.parse(await readFile(path, 'utf8'))
+ } catch (error) {
+ throw new Error(`SSH relay runtime manifest signing request is invalid JSON: ${error.message}`)
+ }
+ decodeSshRelayRuntimeManifestSigningRequestArtifact(artifact)
+ return artifact
+}
+
+async function exclusiveOutputDirectory(outputDirectory) {
+ const absolute = resolve(outputDirectory)
+ const parent = resolve(await realpath(dirname(absolute)))
+ const parentMetadata = await lstat(parent)
+ if (!parentMetadata.isDirectory() || parentMetadata.isSymbolicLink()) {
+ throw new Error('SSH relay runtime manifest signing output parent must be a real directory')
+ }
+ const output = resolve(parent, basename(absolute))
+ try {
+ await lstat(output)
+ } catch (error) {
+ if (error.code === 'ENOENT') {
+ return output
+ }
+ throw error
+ }
+ throw new Error(
+ 'SSH relay runtime manifest signing requires an exclusive absent output directory'
+ )
+}
+
+export async function writeSshRelayRuntimeManifestSigningResult({
+ requestArtifact,
+ seedBase64,
+ outputDirectory
+}) {
+ const result = signSshRelayRuntimeManifestRequest({ requestArtifact, seedBase64 })
+ const output = await exclusiveOutputDirectory(outputDirectory)
+ let created = false
+ try {
+ await mkdir(output, { mode: 0o700 })
+ created = true
+ // Why: the protected job may return only the authenticated key identity and detached signature.
+ await writeFile(joinResultPath(output), `${JSON.stringify(result)}\n`, {
+ flag: 'wx',
+ mode: 0o600
+ })
+ return result
+ } catch (error) {
+ if (created) {
+ await rm(output, { recursive: true, force: true })
+ }
+ throw error
+ }
+}
+
+function joinResultPath(output) {
+ return resolve(output, 'signing-result.json')
+}
+
+export function parseSshRelayRuntimeManifestSeedSigningArguments(argv) {
+ const options = {}
+ const fields = new Map([
+ ['--request', 'requestPath'],
+ ['--output-directory', 'outputDirectory']
+ ])
+ for (let index = 0; index < argv.length; index += 2) {
+ const field = fields.get(argv[index])
+ const value = argv[index + 1]
+ if (!field || !value || value.startsWith('--') || options[field]) {
+ throw new Error(`Invalid SSH relay runtime manifest seed signing argument: ${argv[index]}`)
+ }
+ options[field] = resolve(value)
+ }
+ for (const field of fields.values()) {
+ if (!options[field]) {
+ throw new Error(`Missing SSH relay runtime manifest seed signing argument: ${field}`)
+ }
+ }
+ return options
+}
+
+async function main() {
+ const options = parseSshRelayRuntimeManifestSeedSigningArguments(process.argv.slice(2))
+ const requestArtifact = await readSshRelayRuntimeManifestSigningRequestArtifact(
+ options.requestPath
+ )
+ const result = await writeSshRelayRuntimeManifestSigningResult({
+ requestArtifact,
+ seedBase64: process.env.SSH_RELAY_RUNTIME_MANIFEST_SEED,
+ outputDirectory: options.outputDirectory
+ })
+ process.stdout.write(`${JSON.stringify({ keyId: result.keyId })}\n`)
+}
+
+if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) {
+ main().catch((error) => {
+ process.stderr.write(
+ `SSH relay runtime manifest seed signing failed: ${error.stack ?? error}\n`
+ )
+ process.exitCode = 1
+ })
+}
+
+export const SSH_RELAY_RUNTIME_MANIFEST_SEED_SIGNING_LIMITS = Object.freeze({
+ maximumRequestArtifactBytes: MAX_REQUEST_ARTIFACT_BYTES
+})
diff --git a/config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs b/config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs
new file mode 100644
index 00000000000..b683554de18
--- /dev/null
+++ b/config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs
@@ -0,0 +1,152 @@
+import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
+import { tmpdir } from 'node:os'
+import { join } from 'node:path'
+
+import nacl from 'tweetnacl'
+import { afterEach, describe, expect, it } from 'vitest'
+
+import { createSshRelayArtifactTestManifest } from '../../src/main/ssh/ssh-relay-artifact-test-manifest.ts'
+import { assembleCanonicalSshRelayRuntimeManifest } from './ssh-relay-runtime-manifest-assembly.mjs'
+import {
+ createSshRelayRuntimeManifestSigningRequest,
+ finalizeSshRelayRuntimeManifestSigningHandoff,
+ sshRelayRuntimeManifestKeyId
+} from './ssh-relay-runtime-manifest-signing-handoff.mjs'
+import {
+ decodeSshRelayRuntimeManifestSigningRequestArtifact,
+ encodeSshRelayRuntimeManifestSigningRequestArtifact,
+ signSshRelayRuntimeManifestRequest,
+ writeSshRelayRuntimeManifestSigningResult
+} from './ssh-relay-runtime-manifest-seed-signing.mjs'
+
+const temporaryDirectories = []
+const seed = Uint8Array.from({ length: 32 }, (_, index) => index)
+const seedBase64 = Buffer.from(seed).toString('base64')
+const keyPair = nacl.sign.keyPair.fromSeed(seed)
+
+function request() {
+ const { signatures: _signatures, ...unsigned } = createSshRelayArtifactTestManifest()
+ const canonical = assembleCanonicalSshRelayRuntimeManifest(unsigned).canonicalBytes
+ return createSshRelayRuntimeManifestSigningRequest(canonical)
+}
+
+afterEach(async () => {
+ await Promise.all(
+ temporaryDirectories.splice(0).map((path) => rm(path, { recursive: true, force: true }))
+ )
+})
+
+describe('SSH relay runtime protected manifest seed signing', () => {
+ it('round-trips a bounded canonical request and returns only key ID plus signature', () => {
+ const source = request()
+ const artifact = encodeSshRelayRuntimeManifestSigningRequestArtifact(source)
+ const decoded = decodeSshRelayRuntimeManifestSigningRequestArtifact(artifact)
+ const result = signSshRelayRuntimeManifestRequest({ requestArtifact: artifact, seedBase64 })
+
+ expect(decoded).toEqual(source)
+ expect(Object.keys(artifact).sort()).toEqual([
+ 'algorithm',
+ 'payloadBase64',
+ 'payloadSha256',
+ 'payloadSize',
+ 'schemaVersion'
+ ])
+ expect(result).toEqual({
+ keyId: sshRelayRuntimeManifestKeyId(keyPair.publicKey),
+ signature: Buffer.from(nacl.sign.detached(source.canonicalBytes, keyPair.secretKey)).toString(
+ 'base64'
+ )
+ })
+ expect(
+ finalizeSshRelayRuntimeManifestSigningHandoff({
+ request: decoded,
+ signingResults: [result],
+ acceptedKeys: [{ keyId: result.keyId, publicKey: keyPair.publicKey }]
+ }).manifest.signatures
+ ).toEqual([{ algorithm: 'ed25519-v1', ...result }])
+ })
+
+ it.each([
+ ['', /seed/i],
+ ['not-base64', /seed|base64/i],
+ [`${seedBase64}\n`, /seed|base64/i],
+ [Buffer.alloc(31).toString('base64'), /32 bytes|seed/i],
+ [Buffer.alloc(33).toString('base64'), /32 bytes|seed/i]
+ ])('rejects a malformed or non-canonical seed without a result', (candidate, message) => {
+ expect(() =>
+ signSshRelayRuntimeManifestRequest({
+ requestArtifact: encodeSshRelayRuntimeManifestSigningRequestArtifact(request()),
+ seedBase64: candidate
+ })
+ ).toThrow(message)
+ })
+
+ it('rejects request field, size, hash, canonical-byte, and base64 drift', () => {
+ const valid = encodeSshRelayRuntimeManifestSigningRequestArtifact(request())
+ const cases = [
+ { ...valid, extra: true },
+ { ...valid, algorithm: 'rsa-v1' },
+ { ...valid, payloadSize: valid.payloadSize + 1 },
+ { ...valid, payloadSha256: `sha256:${'f'.repeat(64)}` },
+ { ...valid, payloadBase64: `${valid.payloadBase64}\n` },
+ { ...valid, payloadBase64: Buffer.from('{}').toString('base64'), payloadSize: 2 }
+ ]
+ for (const artifact of cases) {
+ expect(() =>
+ signSshRelayRuntimeManifestRequest({ requestArtifact: artifact, seedBase64 })
+ ).toThrow()
+ }
+ })
+
+ it('writes only an exclusive bounded result and removes partial output on failure', async () => {
+ const root = await mkdtemp(join(tmpdir(), 'orca-runtime-manifest-seed-signing-'))
+ temporaryDirectories.push(root)
+ const outputDirectory = join(root, 'result')
+ const result = await writeSshRelayRuntimeManifestSigningResult({
+ requestArtifact: encodeSshRelayRuntimeManifestSigningRequestArtifact(request()),
+ seedBase64,
+ outputDirectory
+ })
+ expect(
+ JSON.parse(await readFile(join(outputDirectory, 'signing-result.json'), 'utf8'))
+ ).toEqual(result)
+ await expect(
+ writeSshRelayRuntimeManifestSigningResult({
+ requestArtifact: encodeSshRelayRuntimeManifestSigningRequestArtifact(request()),
+ seedBase64,
+ outputDirectory
+ })
+ ).rejects.toThrow(/exclusive|absent/i)
+
+ const failed = join(root, 'failed')
+ await expect(
+ writeSshRelayRuntimeManifestSigningResult({
+ requestArtifact: { invalid: true },
+ seedBase64,
+ outputDirectory: failed
+ })
+ ).rejects.toThrow()
+ await expect(readFile(join(failed, 'signing-result.json'))).rejects.toMatchObject({
+ code: 'ENOENT'
+ })
+ })
+
+ it('rejects a symlinked request path before reading CLI input', async () => {
+ const root = await mkdtemp(join(tmpdir(), 'orca-runtime-manifest-seed-signing-'))
+ temporaryDirectories.push(root)
+ const target = join(root, 'request.json')
+ const linked = join(root, 'linked.json')
+ await writeFile(
+ target,
+ JSON.stringify(encodeSshRelayRuntimeManifestSigningRequestArtifact(request()))
+ )
+ await expect(
+ import('node:fs/promises').then(({ symlink }) => symlink(target, linked))
+ ).resolves.toBeUndefined()
+ const { readSshRelayRuntimeManifestSigningRequestArtifact } =
+ await import('./ssh-relay-runtime-manifest-seed-signing.mjs')
+ await expect(readSshRelayRuntimeManifestSigningRequestArtifact(linked)).rejects.toThrow(
+ /regular file|symlink/i
+ )
+ })
+})
diff --git a/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist-summary.md b/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist-summary.md
index 68edae4cb89..8d895aaeafc 100644
--- a/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist-summary.md
+++ b/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist-summary.md
@@ -240,6 +240,10 @@ complete a box.
hash-bound descriptors/receipts. The active slice is the callable, disconnected aggregate and
protected Ed25519-signing workflow contract. The environment/seed are not provisioned, so live
signing remains blocked and no release, desktop, publication, or tuple consumer is connected.
+ The missing-workflow/seed-signer RED is
+ `E-M4-PROTECTED-MANIFEST-WORKFLOW-LOCAL-RED-001`; the seed signer is locally green under
+ `E-M4-PROTECTED-MANIFEST-SEED-LOCAL-001`, while the filesystem aggregate command and workflow
+ remain open.
- [ ] Embed the exact signed manifest and accepted keys in each desktop build.
- [ ] Upload to a draft release, read back, re-hash, and execute the downloaded archives.
- [ ] Test timeouts, retries, approval denial, signing failure, partial output, and draft recovery.
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 351efdd6526..50e1eb39676 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
@@ -9,7 +9,7 @@ work; keep exact commands, runner identities, hashes, metrics, and residual gaps
Date created: 2026-07-14
Last updated: 2026-07-15
Current phase: Milestone 4 / Work Package 3 disconnected aggregate and protected manifest-signing workflow contract — **In progress — 2026-07-15, Codex implementation owner**. Linux aggregate-ready finalization is closed locally and on exact-head native x64/arm64 runners under E-M4-LINUX-FINALIZATION-LOCAL-RED-001, E-M4-LINUX-FINALIZATION-LOCAL-001, and E-M4-LINUX-FINALIZATION-CI-001. The active package must consume only the six exact aggregate-ready outputs, prepare canonical bytes credential-free, expose only those bytes to the tag-restricted `relay-runtime-manifest-signing` environment, accept only key ID plus Ed25519 signature, reconstruct and verify before final output, and fail closed on missing/extra/mutated inputs, approval/secret/signing failure, timeout, or partial output. It remains callable and disconnected. Release-cut, desktop builds, publication, and every tuple stay disconnected; production/default behavior is unchanged.
-Session checkpoint: **In progress — 2026-07-15, Codex implementation owner** — exact-head run 29419759256 at `91f59d19e5251fb7b6c9f6d397cd9cd82b43cbdf` passes all six native builds, both Linux userland supplements, and Windows x64 baseline. Windows arm64 fails only the retained build-floor gate after successful runtime verification (hosted 26200 versus required 26100). Downloaded artifacts 8344803641 and 8344824674 contain the expected Linux x64/arm64 descriptors and finalization receipts, whose tuple/content/archive/metadata bindings and smoke/resource metrics were inspected under E-M4-LINUX-FINALIZATION-CI-001. Golden E2E passes. PR Checks attempt 1 exposed one unrelated terminal-routing assertion after 29,944 tests passed; the focused test passes locally and exact-head attempt 2 passes all 29,945 tests, unpacked build, and packaged CLI smoke under E-M4-LINUX-FINALIZATION-PR-CHECKS-RED-001 and E-M4-LINUX-FINALIZATION-PR-CHECKS-001. No signing credential, aggregate workflow, release consumer, publication path, desktop consumer, tuple enablement, or production/default change is connected. Legacy remains the production default, and merge to `main` remains prohibited.
+Session checkpoint: **In progress — 2026-07-15, Codex implementation owner** — exact-head run 29419759256 at `91f59d19e5251fb7b6c9f6d397cd9cd82b43cbdf` passes all six native builds, both Linux userland supplements, and Windows x64 baseline. Windows arm64 fails only the retained build-floor gate after successful runtime verification (hosted 26200 versus required 26100). Downloaded artifacts 8344803641 and 8344824674 contain the expected Linux x64/arm64 descriptors and finalization receipts, whose tuple/content/archive/metadata bindings and smoke/resource metrics were inspected under E-M4-LINUX-FINALIZATION-CI-001. Golden E2E and replacement PR Checks pass. The protected seed signer is now locally green under E-M4-PROTECTED-MANIFEST-WORKFLOW-LOCAL-RED-001 and E-M4-PROTECTED-MANIFEST-SEED-LOCAL-001: canonical request serialization, exact base64 32-byte seed validation, signature-only output, drift/symlink rejection, and exclusive failure cleanup pass, and both native contract families execute the tests. The callable workflow remains intentionally absent/red while the filesystem prepare/finalize command is implemented next. No signing credential, aggregate workflow, release consumer, publication path, desktop consumer, tuple enablement, or production/default change is connected. Legacy remains the production default, and merge to `main` remains prohibited.
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)
@@ -10704,6 +10704,78 @@ through command-finished foreground confirmation` receives `csi-u` instead of `a
- Follow-up: checkpoint the Linux finalization evidence and start the disconnected aggregate and
protected manifest-signing workflow RED.
+### E-M4-PROTECTED-MANIFEST-WORKFLOW-LOCAL-RED-001 — Callable protected signing workflow is absent
+
+- Date: 2026-07-15
+- Owner: Codex implementation owner
+- Source: uncommitted purpose-named test atop pushed head
+ `e5dfffaaa2df55b221c5ee30699ff8fe814b91aa`; draft PR #8741.
+- Runner/remote/network: local macOS 26.2 arm64, Node v26.0.0 and pnpm 10.24.0. Static repository
+ workflow-source read only; no Actions runner, environment approval, secret, signer, artifact
+ download, release, desktop consumer, SSH host, or enabled tuple.
+- Command:
+ `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-manifest-signing-workflow.test.mjs`.
+- Result: expected FAIL, 1 file / 1 test in 182 ms Vitest / 0.89 seconds wall,
+ 131,743,744-byte maximum RSS, 95,966,656-byte peak footprint, zero swaps. The only failure is
+ `ENOENT` for `.github/workflows/ssh-relay-runtime-manifest-signing.yml`.
+- Seed-signer prerequisite RED:
+ `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs`
+ — expected FAIL before collection because
+ `config/scripts/ssh-relay-runtime-manifest-seed-signing.mjs` is absent; 196 ms Vitest / 0.90
+ seconds wall, 132,022,272-byte maximum RSS, 96,228,776-byte peak footprint, zero swaps. The test
+ defines canonical request serialization, exact 32-byte base64 seed handling, signature-only
+ output, request/seed drift rejection, exclusive output cleanup, and symlink rejection.
+- Oracle proved: no callable workflow currently enforces the required three-stage boundary: exact
+ six-artifact credential-free preparation; one protected `relay-runtime-manifest-signing` job with
+ the sole seed reference and signature-only output; then credential-free reconstruction and final
+ verification. The RED also requires SHA-pinned actions, strict timeouts, no wildcard artifact
+ merge, read-only permissions, and complete release/desktop/rehearsal disconnection.
+- Does not prove: implementation, signer seed validation, file-based prepare/finalize behavior,
+ Actions execution, environment protection, real signatures, publication, desktop embedding, SSH
+ behavior, or an enabled tuple.
+- Follow-up: implement the seed signer and exclusive filesystem prepare/finalize commands with
+ hostile-input tests, then add the callable workflow and make this contract green without
+ connecting any consumer.
+
+### E-M4-PROTECTED-MANIFEST-SEED-LOCAL-001 — Protected seed signer passes locally
+
+- Date: 2026-07-15
+- Owner: Codex implementation owner
+- Source: local implementation atop pushed head `e5dfffaaa2df55b221c5ee30699ff8fe814b91aa`;
+ draft PR #8741.
+- Runner/remote/network: local macOS 26.2 arm64, Node v26.0.0 and pnpm 10.24.0. Test-only in-memory
+ Ed25519 seeds and local temporary files; no GitHub Environment, Actions secret, release, desktop
+ consumer, publication, SSH host, or enabled tuple.
+- Focused command:
+ `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs config/scripts/ssh-relay-runtime-manifest-assembly.test.mjs`
+ — PASS, 3 files / 20 tests in 638 ms Vitest / 1.30 seconds wall, 188,612,608-byte maximum RSS,
+ 96,163,336-byte peak footprint, zero swaps.
+- Broad release command excluding the deliberately still-red workflow-source test:
+ `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 $(rg --files config/scripts | rg '/ssh-relay.*\\.test\\.mjs$' | rg -v 'ssh-relay-runtime-manifest-signing-workflow\\.test\\.mjs$')`
+ — PASS, 49 files / 255 tests in 8.54 seconds Vitest / 9.46 seconds wall,
+ 188,858,368-byte maximum RSS, 96,523,568-byte peak footprint, zero swaps. The unfiltered 50-file
+ run passes the same 49 files / 255 tests and fails only the recorded missing-workflow RED.
+- Desktop parity:
+ `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 src/main/ssh/ssh-relay-artifact-schema.test.ts src/main/ssh/ssh-relay-manifest-signature.test.ts src/main/ssh/ssh-relay-release-asset.test.ts`
+ — PASS, 3 files / 48 tests in 493 ms Vitest / 1.12 seconds wall, 131,858,432-byte maximum RSS,
+ 96,032,120-byte peak footprint, zero swaps.
+- Static results: `node --check`, focused `oxlint`, and focused `oxfmt --check` pass. `pnpm run
+typecheck` passes in 1.88 seconds wall. Full `pnpm run lint` passes in 9.26 seconds wall with all 41
+ reliability gates, the 355-entry max-lines ratchet, bundled-skill, localization catalog/parity,
+ and localization coverage gates; all 26 warnings are in untouched existing files.
+- Oracle proved: request artifacts contain only the exact canonical payload plus algorithm/hash/size
+ bindings; malformed fields, noncanonical base64, payload drift, and noncanonical manifest bytes
+ fail. Only a canonical base64 32-byte seed is accepted. Output contains exactly key ID plus the
+ detached 64-byte signature, is created in an exclusive directory, and is removed on failure.
+ Symlinked request files are rejected. Both POSIX and Windows native artifact contract families now
+ syntax-check and run the purpose suite without exposing a secret.
+- Does not prove: a real GitHub Environment or seed, reviewer approval, the filesystem aggregate
+ prepare/finalize boundary, the callable workflow, Actions execution, publication, desktop
+ embedding, SSH behavior, or an enabled tuple.
+- Follow-up: implement the exclusive six-artifact filesystem prepare/finalize command, including
+ receipt/path/mutation/accepted-key/signature/partial-output failures, before adding the callable
+ workflow.
+
## Accepted Gaps
No product gap is accepted merely because it appears in this list. Each entry requires explicit
@@ -10762,14 +10834,15 @@ The project is not complete until every applicable item below is checked with ev
## Next Required Action
-Checkpoint E-M4-LINUX-FINALIZATION-CI-001 and the green PR Checks replacement. Then begin a
-purpose-named RED for the callable, disconnected aggregate/immutable-manifest workflow: consume all
-six exact aggregate-ready artifacts, prepare canonical bytes without credentials, isolate the
-base64 32-byte seed in the tag-restricted `relay-runtime-manifest-signing` environment, return only
-key ID plus signature, reconstruct and verify before emitting final output, and remove partial
-output on every failure. The environment and secret remain unprovisioned, so live signing evidence
-must stay BLOCKED. Keep Windows arm64 build 26100, macOS 13.5, Linux kernel 4.18, release-cut,
-desktop builds, publication, and every tuple separately gated. Do not merge to `main`; retain every
+Checkpoint the locally proven protected seed signer and require its contract on all six native test
+families. Then implement the exclusive filesystem prepare/finalize command that collects only the
+six exact aggregate-ready artifacts, binds receipts and accepted public keys, serializes canonical
+bytes without credentials, reconstructs after signature return, and removes partial output on every
+failure. Only after that command is green may the still-red callable workflow isolate the base64
+32-byte seed in the tag-restricted `relay-runtime-manifest-signing` environment. The environment,
+accepted production keys, and secret remain unprovisioned, so live signing evidence must stay
+BLOCKED. Keep Windows arm64 build 26100, macOS 13.5, Linux kernel 4.18, release-cut, desktop builds,
+publication, and every tuple separately gated. Do not merge to `main`; retain every
production/default gate.
Cross-family Layer B targets, the protected manifest-signing environment, oldest-baseline/native-