diff --git a/.dockerignore b/.dockerignore index df7fc23d6b6..597c1fa5cab 100644 --- a/.dockerignore +++ b/.dockerignore @@ -48,6 +48,7 @@ packages/paperclip-runner/test-fixtures/** !packages/paperclip-runner/test-fixtures/pi-acp packages/paperclip-runner/test-fixtures/pi-acp/** !packages/paperclip-runner/test-fixtures/pi-acp/profile-v18-identity.json +!packages/paperclip-runner/test-fixtures/pi-acp/profile-v19-identity.json !packages/paperclip-runner/docs/capability-contract.md # check:runner-workflow-traceability access()es every regression test the # stress-traceability spec names — those are src/**/*.test.ts files, so diff --git a/doc/plans/2026-10-02-pi-production-readiness.md b/doc/plans/2026-10-02-pi-production-readiness.md index 7c6b6f24da0..297bea79a84 100644 --- a/doc/plans/2026-10-02-pi-production-readiness.md +++ b/doc/plans/2026-10-02-pi-production-readiness.md @@ -14,8 +14,9 @@ Done and a succeeded native run; three follow-up turns with continuity; browser questions and answers; plan approval; same-turn steering and denial; Stop; and controller recovery with the original native question and run. Use the retained `b696e131ae32a82418e570b32f4727b5adb14e49` packages and cloud image, the approved -Sonnet 4.6 fixture and low thinking. No local Docker, provider expansion, image -rebuild, or accounting change is needed for this scope. +Sonnet 4.6 fixture and low thinking. No local Docker, provider expansion, or +accounting change is in scope. Rebuild the cloud runtime only when a confirmed +core-path defect requires a production change. The first current-cloud file attempt, `pi-core-0-1791470050`, edited, validated, published and finished through the real product. Its strict definition-4 grade @@ -29,6 +30,41 @@ canonical files (91,468,056 bytes) are retained with archive SHA-256 independent process and scratch cleanup pass. Definition 5 fences the unchanged command for literal Markdown paste; the one-command grader stays unchanged. +The following current-cloud paths pass with runtime `b696e131`, harness +`ee3b094d35719e4dd7cbc791d1924205c4fa474f` and the retained immutable image: + +| Core path | Canonical campaign | Retained evidence | +| --- | --- | --- | +| File edit, one exact successful command, authenticated public download, registered deliverable, finish, Done and finalized copy-back | `pi-core-0-1791470879` | 23 files; archive SHA256 `9a1c41e2ccad75f89a069ff571a3aa9f8cb94ae80c1bd397f7c886338b9a09bd`; definition 5 | +| Three browser follow-up turns retain native session/process/workspace identity and append the earlier work | `pi-core-1-1791471072` | 23 files; archive SHA256 `d10310a2720a0d6c0636ce389fc6cc5faa887cc5c95bd697cdf0172619973609`; definition 2 | +| Human plan approval resumes work and completion through the public product | `pi-core-3-1791472300` | 22 files; archive SHA256 `8c069ff176cb94166429901957f80e8b22c36ddf0f2047193889c4b7059aedf3`; definition 5 | + +Every listed canonical result and independent cleanup check passes. All retained +files are hash-verified. These are exact-source passes; a changed runtime must +be checked again before they qualify that runtime. + +Native-question campaign `pi-core-2-1791471416` remains failed. Its original +machine classification is `transient_infrastructure`; the run times out after +120 seconds. The evidence shows three rejected native-question calls: empty +arguments, then two `select` calls with `options` encoded as a JSON string. The +model subsequently asks confirmation while the browser waits for color. All +45 canonical files (177,803,509 bytes) are retained with archive SHA256 +`66c801596d81b909ac2ad8004d885ddf69b7478d9ab9a0cce11a52ebfe8a6e28`; +independent retirement and scratch cleanup pass. Do not regrade this failure or +retry the unchanged runtime. + +The production question schema has method-specific branches but no root field +definitions. Profile 19 exposes the same field types at the root and keeps every +method-specific constraint and runtime validator. Root-only gateway tool +rendering is the inferred compatibility cause; a fresh real question pass is +still required. Stringified options, absent arguments and cross-method fields +remain invalid. The existing 38 extension tests pass on the pinned Node 24.21.0. +All three prior closure hashes are independently reproduced from the retained +full manifest and reviewed Node pins; only `extensions/paperclip.js` changes. +No model allowlist, model fallback, credential policy or question-answer coercion +is added. The corrected runtime requires the normal hosted cloud build and +public-install checks before another paid question attempt. + ## Correct cloud memory-read authority — 2026-10-08 Frozen runtime/image `b696e131ae32a82418e570b32f4727b5adb14e49` passes all diff --git a/packages/paperclip-runner/acpx-profiles.json b/packages/paperclip-runner/acpx-profiles.json index daab3f8ffac..94ba0d42884 100644 --- a/packages/paperclip-runner/acpx-profiles.json +++ b/packages/paperclip-runner/acpx-profiles.json @@ -14,12 +14,12 @@ "requiresProviderPolicy": false }, "pi": { - "agentProfileVersion": 18, + "agentProfileVersion": 19, "agentServerPackage": "pi-acp", "agentServerVersion": "0.0.33", "agentRuntimePackage": "@earendil-works/pi-coding-agent", "agentRuntimeVersion": "1.0.0", - "commandDigest": "sha256:9d3e7d8269f1a0af94616552dfc69671932688b81dbbd5bab9ef356b3a9cbccb", + "commandDigest": "sha256:b7647ebf97f802ca053ec3384c912bf0e8d18eba308d27397bb1d95a37220825", "requiresProviderPolicy": true }, "cursor": { diff --git a/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs b/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs index f6fa38cc0f3..1a533689d8a 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs @@ -3184,7 +3184,7 @@ mod tests { #[test] fn pi_profile_matches_published_identity_and_rejects_prior_profiles() { let published: Value = serde_json::from_str(include_str!( - "../../../../test-fixtures/pi-acp/profile-v18-identity.json" + "../../../../test-fixtures/pi-acp/profile-v19-identity.json" )) .unwrap(); let mut value = descriptor("codex"); @@ -3204,6 +3204,7 @@ mod tests { include_str!("../../../../test-fixtures/pi-acp/profile-v15-identity.json"), include_str!("../../../../test-fixtures/pi-acp/profile-v16-identity.json"), include_str!("../../../../test-fixtures/pi-acp/profile-v17-identity.json"), + include_str!("../../../../test-fixtures/pi-acp/profile-v18-identity.json"), ] { let prior: Value = serde_json::from_str(prior).unwrap(); value["commandDigest"] = prior["commandDigest"].clone(); diff --git a/packages/paperclip-runner/runner/crates/runner-core/src/generated_acpx_profiles.rs b/packages/paperclip-runner/runner/crates/runner-core/src/generated_acpx_profiles.rs index 12c2de52c0e..058ed3bd392 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/src/generated_acpx_profiles.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/src/generated_acpx_profiles.rs @@ -29,7 +29,7 @@ pub(crate) fn acpx_release_profile(agent: &str) -> Option { agent_runtime_package: Some("@earendil-works/pi-coding-agent"), agent_runtime_version: Some("1.0.0"), command_digest: - "sha256:9d3e7d8269f1a0af94616552dfc69671932688b81dbbd5bab9ef356b3a9cbccb", + "sha256:b7647ebf97f802ca053ec3384c912bf0e8d18eba308d27397bb1d95a37220825", requires_provider_policy: true, }, "cursor" => AcpxReleaseProfile { diff --git a/packages/paperclip-runner/scripts/generate-acpx-profiles.mjs b/packages/paperclip-runner/scripts/generate-acpx-profiles.mjs index 1130a61c394..ff5a4abf51b 100644 --- a/packages/paperclip-runner/scripts/generate-acpx-profiles.mjs +++ b/packages/paperclip-runner/scripts/generate-acpx-profiles.mjs @@ -39,7 +39,7 @@ const { commandDigest, ...attestation } = contract; assert.equal(commandDigest, `sha256:${createHash("sha256").update(canonicalJson(attestation)).digest("hex")}`); assert.equal(contract.acpxPatchSha256, createHash("sha256") .update(await readFile(new URL("../../patches/acpx@0.13.1.patch", root))).digest("hex")); -for (const [agent, path] of [["pi", "test-fixtures/pi-acp/profile-v18-identity.json"], ["copilot", "test/fixtures/copilot-profile-v16-identity.json"]]) { +for (const [agent, path] of [["pi", "test-fixtures/pi-acp/profile-v19-identity.json"], ["copilot", "test/fixtures/copilot-profile-v16-identity.json"]]) { const identity = await readJson(path); assert.equal(manifest.profiles[agent].agentProfileVersion, identity.declaration.agentProfileVersion); assert.equal(manifest.profiles[agent].commandDigest, identity.commandDigest); diff --git a/packages/paperclip-runner/src/drivers/acpx/generated-profiles.ts b/packages/paperclip-runner/src/drivers/acpx/generated-profiles.ts index 7dad9a72662..bc711146f1c 100644 --- a/packages/paperclip-runner/src/drivers/acpx/generated-profiles.ts +++ b/packages/paperclip-runner/src/drivers/acpx/generated-profiles.ts @@ -22,12 +22,12 @@ export const QUALIFIED_ACPX_PROFILE_DATA = { "protocolVersion": 1, "acpxVersion": "0.13.1", "agent": "pi", - "agentProfileVersion": 18, + "agentProfileVersion": 19, "agentServerPackage": "pi-acp", "agentServerVersion": "0.0.33", "agentRuntimePackage": "@earendil-works/pi-coding-agent", "agentRuntimeVersion": "1.0.0", - "commandDigest": "sha256:9d3e7d8269f1a0af94616552dfc69671932688b81dbbd5bab9ef356b3a9cbccb", + "commandDigest": "sha256:b7647ebf97f802ca053ec3384c912bf0e8d18eba308d27397bb1d95a37220825", "permissionPolicy": "interactive" }, "cursor": { diff --git a/packages/paperclip-runner/src/drivers/acpx/pi-closure-pins.ts b/packages/paperclip-runner/src/drivers/acpx/pi-closure-pins.ts index bd5a9010901..918a29a8865 100644 --- a/packages/paperclip-runner/src/drivers/acpx/pi-closure-pins.ts +++ b/packages/paperclip-runner/src/drivers/acpx/pi-closure-pins.ts @@ -7,7 +7,7 @@ * three pins. Never accept a digest supplied only by an installed manifest. */ export const PI_DISTRIBUTION_CLOSURE_SHA256 = Object.freeze({ - "darwin-arm64": "8b85caad950fc720eabd80d7b67146b5b2106c66aecf1797993b90a3568ddc7f", - "darwin-x64": "c66bfff68705627b3c5589e038080b284a04027a0a0a3371a54a657a80787789", - "linux-x64": "a1b2797c5ca8245b441b0cc0e18f09463d9d896bd52631874320d77a09a4736d", + "darwin-arm64": "e076276c674dfffccbb488883e18571d77d7225d801fabf5c8391773ddbbfc6c", + "darwin-x64": "eafd44e672dec4966ef6f038620f003e5d492c889d475886cd66be2e9c2bff1d", + "linux-x64": "f493df174cfecba3c31c524aa486ae37663cd68f8fcc0d9556e3f615c4a40ce9", }); diff --git a/packages/paperclip-runner/src/drivers/acpx/pi-installation.test.ts b/packages/paperclip-runner/src/drivers/acpx/pi-installation.test.ts index 5747c5b442c..34cabe12445 100644 --- a/packages/paperclip-runner/src/drivers/acpx/pi-installation.test.ts +++ b/packages/paperclip-runner/src/drivers/acpx/pi-installation.test.ts @@ -56,11 +56,19 @@ describe("Pi installation factory", () => { expect(current.commandDigest).not.toBe(prior.commandDigest); }); + it("preserves profile 18 and binds root question field types in profile 19", async () => { + const prior = JSON.parse(await readFile(new URL("../../../test-fixtures/pi-acp/profile-v18-identity.json", import.meta.url), "utf8")); + const current = JSON.parse(await readFile(new URL("../../../test-fixtures/pi-acp/profile-v19-identity.json", import.meta.url), "utf8")); + expect(Object.keys(current.declaration).filter(key => JSON.stringify(current.declaration[key]) !== JSON.stringify(prior.declaration[key])).sort()) + .toEqual(["agentProfileVersion", "closure", "extensionSha256", "nativeQuestions"]); + expect(current.commandDigest).not.toBe(prior.commandDigest); + }); + it("binds the profile declaration to the reviewed patch and platform closure pins", async () => { const hash = (bytes: string | Uint8Array) => createHash("sha256").update(bytes).digest("hex"); const canonical = (value: any): string => Array.isArray(value) ? `[${value.map(canonical).join(",")}]` : value && typeof value === "object" ? `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}` : JSON.stringify(value); - const identity = JSON.parse(await readFile(new URL("../../../test-fixtures/pi-acp/profile-v18-identity.json", import.meta.url), "utf8")); + const identity = JSON.parse(await readFile(new URL("../../../test-fixtures/pi-acp/profile-v19-identity.json", import.meta.url), "utf8")); const declaration = identity.declaration; expect(declaration.sharedRuntimeContract).toBe("paperclip.acpx-runtime-contract.v1"); expect(identity.commandDigest).toBe(`sha256:${hash(canonical(declaration))}`); @@ -90,21 +98,21 @@ describe("Pi installation factory", () => { it("rejects legacy profiles and tampered executable identities", () => { expect(() => assertPiInstallationProfile(candidate())).not.toThrow(); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 1 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 2 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 3 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 4 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 5 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 6 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 7 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 8 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 9 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 10 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 11 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 12 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 13 })).toThrow("version 18"); - expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 14 })).toThrow("version 18"); - for (const priorVersion of [15, 16, 17]) expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: priorVersion })).toThrow("version 18"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 1 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 2 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 3 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 4 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 5 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 6 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 7 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 8 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 9 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 10 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 11 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 12 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 13 })).toThrow("version 19"); + expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: 14 })).toThrow("version 19"); + for (const priorVersion of [15, 16, 17, 18]) expect(() => assertPiInstallationProfile({ ...candidate(), agentProfileVersion: priorVersion })).toThrow("version 19"); for (const changed of [{ agentServerVersion: "latest" }, { commandDigest: `sha256:${"0".repeat(64)}` }, { agentRuntimePackage: "ambient-pi" }]) { expect(() => assertPiInstallationProfile({ ...candidate(), ...changed })).toThrow("trusted declaration"); } diff --git a/packages/paperclip-runner/src/drivers/acpx/pi-runtime-extension.test.ts b/packages/paperclip-runner/src/drivers/acpx/pi-runtime-extension.test.ts index eed8c692b9b..c11999afac8 100644 --- a/packages/paperclip-runner/src/drivers/acpx/pi-runtime-extension.test.ts +++ b/packages/paperclip-runner/src/drivers/acpx/pi-runtime-extension.test.ts @@ -43,6 +43,8 @@ describe("owned Pi runtime extension", () => { ]; for (const question of questions) expect(validate(question)).toBe(true); for (const question of [ + {}, + { ...questions[0], options: JSON.stringify(questions[0]!.options) }, { ...questions[3], placeholder: "Name" }, { ...questions[2], prefill: "Old draft" }, { ...questions[1], options: [] }, @@ -51,6 +53,21 @@ describe("owned Pi runtime extension", () => { ]) expect(validate(question)).toBe(false); }); + it("exposes native question field types to gateways that describe root properties", async () => { + const { config } = await workspace(); const h = harness(); + await installPiRuntimeExtension(h.api, config); + const schema = h.nativeTools[0]!.parameters; + expect(schema.required).toEqual(["method", "title"]); + expect(schema.properties).toMatchObject({ + method: { type: "string", enum: ["select", "confirm", "input", "editor"] }, + title: { type: "string" }, + options: { type: "array", items: { type: "object", required: ["id", "label"] } }, + message: { type: "string" }, + placeholder: { type: "string" }, + prefill: { type: "string" }, + }); + }); + it("stops Pi 1 cache warming even when native economics recommend a paid refresh", async () => { const { config } = await workspace(); const h = harness(); await installPiRuntimeExtension(h.api, config); diff --git a/packages/paperclip-runner/src/drivers/acpx/pi-runtime-extension.ts b/packages/paperclip-runner/src/drivers/acpx/pi-runtime-extension.ts index df4fe1a59a8..45ce3866cb8 100644 --- a/packages/paperclip-runner/src/drivers/acpx/pi-runtime-extension.ts +++ b/packages/paperclip-runner/src/drivers/acpx/pi-runtime-extension.ts @@ -374,7 +374,17 @@ export async function installPiRuntimeExtension( pi.registerTool({ name: PI_NATIVE_QUESTION_TOOL, label: "Ask a native question", description: "Ask the human a native Pi select, confirm, input, or editor question. Select is single-choice and returns the supplied stable option ID. This cannot approve tools or a Paperclip Plan. For durable task questions or Plan approval use the assigned Paperclip semantic tools. Cancellation is not an answer; confirm false means No or dismissal.", - parameters: { type: "object", anyOf: [ + // Model gateways may render only the root properties when describing a + // tool. Expose the field types there as well as in the strict method + // branches, so an array of options cannot be mistaken for JSON text. + parameters: { type: "object", additionalProperties: false, required: ["method", "title"], properties: { + method: { type: "string", enum: ["select", "confirm", "input", "editor"] }, + title: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH }, + options: { type: "array", minItems: 1, maxItems: 128, items: { type: "object", additionalProperties: false, required: ["id", "label"], properties: { id: { type: "string", pattern: "^[A-Za-z0-9_-]{1,128}$" }, label: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH } } } }, + message: { type: "string", maxLength: 16384 }, + placeholder: { type: "string", maxLength: 16384 }, + prefill: { type: "string", maxLength: 16384 }, + }, anyOf: [ { type: "object", additionalProperties: false, required: ["method", "title", "options"], properties: { method: { const: "select" }, title: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH }, options: { type: "array", minItems: 1, maxItems: 128, items: { type: "object", additionalProperties: false, required: ["id", "label"], properties: { id: { type: "string", pattern: "^[A-Za-z0-9_-]{1,128}$" }, label: { type: "string", maxLength: PI_QUESTION_LABEL_MAX_LENGTH } } } }, diff --git a/packages/paperclip-runner/test-fixtures/pi-acp/profile-v19-identity.json b/packages/paperclip-runner/test-fixtures/pi-acp/profile-v19-identity.json new file mode 100644 index 00000000000..0dbc04a0421 --- /dev/null +++ b/packages/paperclip-runner/test-fixtures/pi-acp/profile-v19-identity.json @@ -0,0 +1,49 @@ +{ + "commandDigest": "sha256:b7647ebf97f802ca053ec3384c912bf0e8d18eba308d27397bb1d95a37220825", + "declaration": { + "schema": "paperclip.acpx_profile_declaration.v1", + "agent": "pi", + "agentProfileVersion": 19, + "acpxVersion": "0.13.1", + "agentServerVersion": "0.0.33", + "agentRuntimeVersion": "1.0.0", + "nodeVersion": "24.21.0", + "closure": { + "darwin-arm64": "e076276c674dfffccbb488883e18571d77d7225d801fabf5c8391773ddbbfc6c", + "darwin-x64": "eafd44e672dec4966ef6f038620f003e5d492c889d475886cd66be2e9c2bff1d", + "linux-x64": "f493df174cfecba3c31c524aa486ae37663cd68f8fcc0d9556e3f615c4a40ce9" + }, + "wrapperSha256": "9d129b3d38772e93e97080aa6c4e574ac5df4e47ce5bc331a484a9fbf8188b36", + "helperSha256": "41e0490b617da0d60e0c8ec58ef311236f945129d99f816cff6897f78da7f91d", + "extensionSha256": "f5818573a355702388072b28926897db546a5cf346b5171f646582ce5f9102a4", + "agentFilesBinding": "registered-runtime-context-v1", + "nativeQuestions": "select-confirm-input-editor-v4-root-field-types", + "pathPolicy": "sdk-normalization-v1", + "mcpToolNames": "provider-safe-exact-source-v1", + "acpxPatchSha256": "00d6af17216cb0cad902b48633eb19bf0ec6b05837a984cb24661fca593f09c1", + "nativeAssistantMessages": "pi1-rpc-deltas-v3-bound-message-and-tool-receipts", + "nativeNotices": "session-extension-v2-bounded-runtime-failure", + "messageProjectionSha256": "17d1e91b948dfa6a56e1905645add52b502041ad843c8d50a13b07956f22aadd", + "noticeProjectionSha256": "014485adc690998e395d334ea3ae67f72be6060a2fc78a1185df7b8d1da28fbf", + "sharedRuntimeContract": "paperclip.acpx-runtime-contract.v1", + "nativeInputDisposition": "queued-only-v1", + "cacheWarming": "disabled-owned-decision-v1", + "thinkingLevel": { + "supported": [ + "off", + "low", + "high", + "max" + ], + "newConfigurationDefault": "low", + "admission": "explicit-native-effective-before-prompt-v1", + "recovery": "mode-bound-v1" + }, + "modelSelection": "caller-selected-native-verified-v1", + "providerConfigurationSourceSha256": "2735ec4b46929f4f59c26cea42e623dfc81016aa7da7bd8399a24caa68a75d6b", + "credentialEnvironmentSourceSha256": "4ee0e9ac56fab8889a4d06b98634bb1797aeda64fcb31e0a404829018c7a12cb", + "runtimeSandboxSourceSha256": "21e1ed2d132886260cf17f956dc21824948bd428b8a0aa05518c508017e66213", + "recoveryIdentitySourceSha256": "f333a24b19ef1b5b5d23ea9778e753f7051690e835ef9e4476a962d8a231c375", + "nativeCancellation": "acknowledged-cancelled-terminal-preserves-usage-v1" + } +} diff --git a/tests/runner-e2e/daytona-image.test.ts b/tests/runner-e2e/daytona-image.test.ts index 3668cedc011..c900942b824 100644 --- a/tests/runner-e2e/daytona-image.test.ts +++ b/tests/runner-e2e/daytona-image.test.ts @@ -90,7 +90,7 @@ describe("runner E2E Daytona image contract", () => { expect(dockerignore).toContain("packages/paperclip-runner/runner/target"); expect(await readFile(path.join(repositoryRoot, ".github/docker-context-checks.Dockerfile"), "utf8")).toContain("node packages/paperclip-runner/scripts/generate-acpx-profiles.mjs --check"); for (const declaration of [ - "test-fixtures/pi-acp/profile-v18-identity.json", + "test-fixtures/pi-acp/profile-v19-identity.json", "test/fixtures/copilot-profile-v16-identity.json", ]) { expect(dockerignore).toContain(`!packages/paperclip-runner/${declaration}`);