diff --git a/packages/paperclip-runner/runner/DURABLE_TRANSPORT.md b/packages/paperclip-runner/runner/DURABLE_TRANSPORT.md index ca4697d8c46..ab44e35d6e1 100644 --- a/packages/paperclip-runner/runner/DURABLE_TRANSPORT.md +++ b/packages/paperclip-runner/runner/DURABLE_TRANSPORT.md @@ -179,6 +179,18 @@ validate the exact Runner identity and acknowledged sequence cut. ### Hosted park and reclaim loop +On Unix builds, `paperclip-runnerd --build-metadata` reports +`privateHostControlVersion: 1` for the existing private fd 4 protocol below. +Other builds omit this field. A consumer must verify the selected executable's +identity and require the exact supported version before using this channel; +an absent or unknown version does not establish support. Recovery and warm-task +versions do not establish it either. Ordinary artifact admission can ignore this +optional field. + +This field describes protocol support only. It does not mean a provider is ready +to park or that a host implements the public `releaseResumeVersion` contract. +Runner readiness checks and host sleep/wake qualification are still required. + A trusted Launcher may pass a connected Unix stream at fd 4 and start durable listener mode with `--host-control-fd 4`. The descriptor is close-on-exec before provider startup. The private channel accepts the `park`, `claim`, and `retire` diff --git a/packages/paperclip-runner/runner/crates/runner-core/src/bin/paperclip-runnerd.rs b/packages/paperclip-runner/runner/crates/runner-core/src/bin/paperclip-runnerd.rs index 4d3c6da791c..895de31d866 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/src/bin/paperclip-runnerd.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/src/bin/paperclip-runnerd.rs @@ -115,7 +115,7 @@ fn install_crypto_provider() { } fn build_metadata() -> serde_json::Value { - json!({ + let mut metadata = json!({ "schema": RUNNERD_BUILD_METADATA_SCHEMA, "binaryName": "paperclip-runnerd", "packageName": "@paperclipai/paperclip-runner", @@ -133,7 +133,11 @@ fn build_metadata() -> serde_json::Value { "maximumVersion": 2 }, "prpTransportModes": ["dial_ws_loopback", "dial_wss", "listen_ws"] - }) + }); + if cfg!(unix) { + metadata["privateHostControlVersion"] = json!(1); + } + metadata } // The publisher seals image installations. Check only path metadata at startup; @@ -726,6 +730,12 @@ mod tests { assert_eq!(metadata["acpxRecoveryIntegrityVersion"], 1); assert!(metadata.get("acpxSourceRecoveryVersion").is_none()); assert!(metadata.get("hostedParkingVersion").is_none()); + assert!(metadata.get("releaseResumeVersion").is_none()); + if cfg!(unix) { + assert_eq!(metadata["privateHostControlVersion"], 1); + } else { + assert!(metadata.get("privateHostControlVersion").is_none()); + } assert_eq!(metadata["schema"], RUNNERD_BUILD_METADATA_SCHEMA); assert_eq!(metadata["binaryContractVersion"], 2); assert_eq!( diff --git a/packages/paperclip-runner/runner/crates/runner-core/tests/local_runner.rs b/packages/paperclip-runner/runner/crates/runner-core/tests/local_runner.rs index e71ef5778a5..eb2eacbf6bd 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/tests/local_runner.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/tests/local_runner.rs @@ -79,6 +79,13 @@ fn runnerd_startup_reports_build_metadata_without_panicking() { let metadata: Value = serde_json::from_slice(&output.stdout).expect("build metadata should be valid JSON"); assert_eq!(metadata["binaryName"], "paperclip-runnerd"); + if cfg!(unix) { + assert_eq!(metadata["privateHostControlVersion"], 1); + } else { + assert!(metadata.get("privateHostControlVersion").is_none()); + } + assert!(metadata.get("hostedParkingVersion").is_none()); + assert!(metadata.get("releaseResumeVersion").is_none()); } #[test] diff --git a/packages/paperclip-runner/src/evals/runnerd-artifact.test.ts b/packages/paperclip-runner/src/evals/runnerd-artifact.test.ts index 4463571f3cf..8f208d99e02 100644 --- a/packages/paperclip-runner/src/evals/runnerd-artifact.test.ts +++ b/packages/paperclip-runner/src/evals/runnerd-artifact.test.ts @@ -28,6 +28,11 @@ describe("runnerd artifact metadata", () => { expect(parsePaperclipRunnerdBuildMetadata(valid)).toEqual(valid); }); + it("accepts private host-control metadata without changing ordinary artifact admission", () => { + expect(parsePaperclipRunnerdBuildMetadata({ ...valid, privateHostControlVersion: 1 })) + .toEqual(valid); + }); + it("rejects an unknown binary metadata schema", () => { expect(() => parsePaperclipRunnerdBuildMetadata({ ...valid, schema: "runnerd/v2" })) .toThrow(PaperclipRunnerdArtifactError);