From fb5150dc44686698dd6e6b7c4b2792fb9f87ed04 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Wed, 5 Aug 2026 12:40:10 -0400 Subject: [PATCH 1/2] Migrate runtimes to canonical SSI import AI assistance: OpenAI gpt-5.6-sol via OpenCode implemented and verified canonical SSI invocation across Cloudflare and browser materialization transports. Chris Huber remains responsible for every line. --- docs/sandbox-session-contract.md | 2 + packages/runtime-cloudflare/README.md | 2 +- .../assets/website-importer-artifact.json | 2 +- .../components/website-importer.json | 2 +- packages/runtime-cloudflare/src/worker.ts | 6 ++- ...class-wp-codebox-agent-runtime-invoker.php | 19 +++++++ ...-browser-contained-site-contract-smoke.php | 10 ++-- tests/browser-runtime-generic-invoker.test.ts | 52 +++++++++++++++++++ tests/cloudflare-runtime.test.ts | 14 +++++ 9 files changed, 102 insertions(+), 7 deletions(-) diff --git a/docs/sandbox-session-contract.md b/docs/sandbox-session-contract.md index 0d49d3229..c0bdd3dd3 100644 --- a/docs/sandbox-session-contract.md +++ b/docs/sandbox-session-contract.md @@ -62,6 +62,8 @@ or staged task payload. Provider plugins are included only when the caller declares them as ordinary `browser_plugins` or `runtime.plugins` dependencies. Browser task and materializer contract creation remains agentic. +Materializer recipes preserve caller-owned `materializer.input` unchanged for direct ability execution. Product transport metadata such as `project_id` and `validation_policy` remains on the materializer envelope rather than being reconstructed into a source-specific artifact contract. + ## Browser Contained Site Handle Browser session, materializer, and task contracts include an additive durable diff --git a/packages/runtime-cloudflare/README.md b/packages/runtime-cloudflare/README.md index 69e635315..a10dd9bc5 100644 --- a/packages/runtime-cloudflare/README.md +++ b/packages/runtime-cloudflare/README.md @@ -58,7 +58,7 @@ The D1 profile registers the configured site identity and creates or converges o Before canonical promotion, the operation checkpoints the exact prepared R2 pointer and expected coordinator version. Recovery skips SSI only when the coordinator's immutable commit receipt matches that complete pointer; a version match alone cannot claim another mutation's commit. The operation remains `publication-pending` after canonical commit until the corresponding immutable R2 publication receipt records promotion, supersession, or orphaning. Its terminal receipt identifies the artifact digest, SSI report, canonical pointer/version, publication identity, site URL, and canonical and terminal completion times. Profiles without a D1 operation repository retain the direct import transaction. -The import transaction boots a dedicated runtime with the pinned Static Site Importer v1.3.6 archive (`fb3679d679c03422fa77f5f33bc549fa869b0ce2bb16f7431705af4fc16b97db`) from R2, invokes its public `static-site-importer/import-website-artifact` ability as the operator-authorized administrator, and requires the canonical quality gate plus zero fallback, core HTML, freeform, and invalid blocks. SSI and its MU loader are runtime-owned and excluded from canonical mutable `wp-content`; generated themes, pages, options, and assets persist normally through MDI/R2. Failed or partial imports discard the PHP runtime without committing. Successful imports persist compact provenance, enqueue affected publication routes, and store at most 20 idempotency receipts in canonical options as a second mutation fence behind the D1 operation record. Exact replay converges without a new revision; reuse with different input returns a conflict. +The import transaction boots a dedicated runtime with the pinned Static Site Importer v1.3.6 archive (`fb3679d679c03422fa77f5f33bc549fa869b0ce2bb16f7431705af4fc16b97db`) from R2 and invokes its public `static-site-importer/import` ability as the operator-authorized administrator. Its exact canonical input uses `operation: "apply"`, an artifact source envelope, deterministic slug/name/site title, activation, overwrite, quality failure, and Cloudflare artifact provenance. The transaction requires the canonical quality gate plus zero fallback, core HTML, freeform, and invalid blocks. SSI and its MU loader are runtime-owned and excluded from canonical mutable `wp-content`; generated themes, pages, options, and assets persist normally through MDI/R2. Failed or partial imports discard the PHP runtime without committing. Successful imports persist compact provenance, enqueue affected publication routes, and store at most 20 idempotency receipts in canonical options as a second mutation fence behind the D1 operation record. Exact replay converges without a new revision; reuse with different input returns a conflict. SSI is extracted only for import requests, so normal browser, mutation, publication, and cron boots retain their existing memory and latency profile. The pinned normal plugin archive bundles Blocks Engine and supports website artifacts without the optional Figma zstd extension; compressed `.fig` import is outside this runtime contract. diff --git a/packages/runtime-cloudflare/assets/website-importer-artifact.json b/packages/runtime-cloudflare/assets/website-importer-artifact.json index d096dc795..cbd13bec9 100644 --- a/packages/runtime-cloudflare/assets/website-importer-artifact.json +++ b/packages/runtime-cloudflare/assets/website-importer-artifact.json @@ -28,7 +28,7 @@ "version_constant": "STATIC_SITE_IMPORTER_VERSION" }, "abilities": { - "website-artifact-import": "static-site-importer/import-website-artifact" + "website-artifact-import": "static-site-importer/import" }, "limits": { "files": 10000, diff --git a/packages/runtime-cloudflare/components/website-importer.json b/packages/runtime-cloudflare/components/website-importer.json index 281643667..361fd9c1d 100644 --- a/packages/runtime-cloudflare/components/website-importer.json +++ b/packages/runtime-cloudflare/components/website-importer.json @@ -23,7 +23,7 @@ "version_constant": "STATIC_SITE_IMPORTER_VERSION" }, "abilities": { - "website-artifact-import": "static-site-importer/import-website-artifact" + "website-artifact-import": "static-site-importer/import" }, "limits": { "files": 10000, diff --git a/packages/runtime-cloudflare/src/worker.ts b/packages/runtime-cloudflare/src/worker.ts index b44baf216..ec5cd1430 100644 --- a/packages/runtime-cloudflare/src/worker.ts +++ b/packages/runtime-cloudflare/src/worker.ts @@ -176,7 +176,11 @@ if (!$ability) { return; } $ability_input = array( - 'artifact' => $artifact, + 'operation' => 'apply', + 'source' => array( + 'type' => 'artifact', + 'artifact' => $artifact, + ), 'slug' => $input['slug'], 'name' => $input['name'], 'site_title' => $input['siteTitle'], diff --git a/packages/wordpress-plugin/src/class-wp-codebox-agent-runtime-invoker.php b/packages/wordpress-plugin/src/class-wp-codebox-agent-runtime-invoker.php index 75151c3bd..c0a6f6071 100644 --- a/packages/wordpress-plugin/src/class-wp-codebox-agent-runtime-invoker.php +++ b/packages/wordpress-plugin/src/class-wp-codebox-agent-runtime-invoker.php @@ -195,6 +195,24 @@ function wp_codebox_browser_runtime_execute_ability( string $ability_name, array } function wp_codebox_browser_runtime_prepare_input( array $payload, array $invocation, string $session_id, array $ability_tools, array $allowed_tool_ids, array $sandbox_tool_ids ): array { + +$materializer = is_array( $payload['materializer'] ?? null ) ? $payload['materializer'] : array(); +$materializer_input = is_array( $materializer['input'] ?? null ) ? $materializer['input'] : null; +$is_direct_materializer_ability = null !== $materializer_input && 'ability' === (string) ( $invocation['type'] ?? 'ability' ); +$materializer_transport = array_filter( + array( + 'task' => isset( $materializer['task'] ) ? (string) $materializer['task'] : '', + 'project_id' => $materializer['project_id'] ?? null, + 'validation_policy' => is_array( $materializer['validation_policy'] ?? null ) ? $materializer['validation_policy'] : array(), + ), + static fn( mixed $value ): bool => null !== $value && '' !== $value && array() !== $value +); + +// A materializer owns its canonical ability input; product metadata remains transport data. +if ( $is_direct_materializer_ability ) { + return $materializer_input; +} + $agent = sanitize_key( (string) ( $payload['agent'] ?? '' ) ); if ( '' === $agent ) { $agent = 'wp-codebox-sandbox'; @@ -231,6 +249,7 @@ function wp_codebox_browser_runtime_prepare_input( array $payload, array $invoca 'caller_session_id' => $session_id, 'task_input' => $payload['task_input'] ?? array(), 'ability_tools' => $ability_tools, + 'materializer' => $materializer_transport, ), ); if ( ! empty( $allowed_tool_ids ) ) { diff --git a/scripts/php-browser-contained-site-contract-smoke.php b/scripts/php-browser-contained-site-contract-smoke.php index e511e3aa8..8b9f0a219 100644 --- a/scripts/php-browser-contained-site-contract-smoke.php +++ b/scripts/php-browser-contained-site-contract-smoke.php @@ -176,8 +176,11 @@ function expect( bool $condition, string $message ): void { 'result_path' => '/tmp/recipe-smoke-result.json', 'invocation' => array( 'type' => 'ability', - 'name' => 'static-site-importer/import-website-artifact', - 'input' => array(), + 'name' => 'static-site-importer/import', + 'input' => array( + 'operation' => 'apply', + 'source' => array( 'type' => 'artifact', 'artifact' => array( 'schema' => 'blocks-engine/php-transformer/site-artifact/v1' ) ), + ), ), ), array( @@ -196,7 +199,8 @@ function expect( bool $condition, string $message ): void { $recipe_steps = is_array( $recipe['runtime']['blueprint']['steps'] ?? null ) ? $recipe['runtime']['blueprint']['steps'] : array(); $recipe_run_php_steps = array_values( array_filter( $recipe_steps, static fn( array $step ): bool => 'runPHP' === ( $step['step'] ?? '' ) ) ); expect( count( $recipe_run_php_steps ) >= 1, 'Expected browser recipe Blueprint to include the runner runPHP step.' ); -expect( str_contains( (string) ( $recipe_run_php_steps[0]['code'] ?? '' ), 'static-site-importer/import-website-artifact' ), 'Expected browser recipe Blueprint runPHP step to execute the requested invocation.' ); +expect( str_contains( (string) ( $recipe_run_php_steps[0]['code'] ?? '' ), 'static-site-importer/import' ), 'Expected browser recipe Blueprint runPHP step to execute the canonical invocation.' ); +expect( ! str_contains( (string) ( $recipe_run_php_steps[0]['code'] ?? '' ), 'static-site-importer/import-website-artifact' ), 'Expected browser recipe Blueprint runPHP step to omit the legacy invocation.' ); $blueprint_method = new ReflectionMethod( WP_Codebox_Abilities::class, 'browser_blueprint_with_runtime' ); $local_package_blueprint = $blueprint_method->invoke( diff --git a/tests/browser-runtime-generic-invoker.test.ts b/tests/browser-runtime-generic-invoker.test.ts index 9e082eaf0..87c6a5765 100644 --- a/tests/browser-runtime-generic-invoker.test.ts +++ b/tests/browser-runtime-generic-invoker.test.ts @@ -9,6 +9,8 @@ const result = await runPhpJson<{ adapter_ability_names: { chat: string } has_principal: boolean agents_api_input: { has_principal: boolean; source: string; peer_agent_call: boolean; effective_agent_id: string } + materializer_input: Record + materializer_transport: Record }>(` define('ABSPATH', ${phpStringLiteral(repoRoot)}); class WP_Error { @@ -56,6 +58,35 @@ WP_Codebox_Agents_API_Adapter::register_runtime_profiles(); $agents_api_payload = array( 'agent' => 'agents-api-agent', 'message' => 'Run adapter runtime', 'task_input' => array() ); $agents_api_invocation = array( 'type' => 'ability', 'name' => 'agents/chat' ); $agents_api_input = wp_codebox_browser_runtime_prepare_input( $agents_api_payload, $agents_api_invocation, 'agents-api-session', array(), array(), array(), array() ); +$materializer_input = array( + 'operation' => 'apply', + 'source' => array( + 'type' => 'artifact', + 'artifact' => array( 'schema' => 'blocks-engine/php-transformer/site-artifact/v1', 'root' => 'website' ), + ), + 'slug' => 'canonical-site', + 'name' => 'Canonical Site', + 'site_title' => 'Canonical Site', + 'activate' => true, + 'overwrite' => true, + 'fail_on_quality' => true, + 'source_metadata' => array( 'generator' => 'wp-build' ), + 'validation_artifacts' => array( 'screenshots' => array( 'before.png', 'after.png' ) ), + 'validation_policy' => array( 'schema' => 'wp-build/visual-parity-validation-policy/v1', 'required' => true ), +); +$materializer_payload = array( + 'agent' => 'generic-agent', + 'message' => 'Apply the canonical materializer.', + 'task_input' => array(), + 'materializer' => array( + 'task' => 'static-site-importer/import', + 'input' => $materializer_input, + 'project_id' => 2220, + 'validation_policy' => array( 'schema' => 'wp-build/visual-parity-validation-policy/v1', 'required' => true ), + ), +); +$materializer_ability_input = wp_codebox_browser_runtime_prepare_input( $materializer_payload, array( 'type' => 'ability', 'name' => 'static-site-importer/import' ), 'materializer-session', array(), array(), array(), array() ); +$materializer_task_input = wp_codebox_browser_runtime_prepare_input( $materializer_payload, $invocation, 'materializer-session', array(), array(), array(), array() ); echo json_encode( array( 'has_agents_api_adapter' => $has_agents_api_adapter, @@ -70,6 +101,8 @@ echo json_encode( array( 'peer_agent_call' => (bool) ( $agents_api_input['client_context']['peer_agent_call'] ?? false ), 'effective_agent_id' => (string) ( $agents_api_input['principal']['effective_agent_id'] ?? '' ), ), + 'materializer_input' => $materializer_ability_input, + 'materializer_transport' => $materializer_task_input['client_context']['materializer'] ?? array(), ), JSON_UNESCAPED_SLASHES ); `) @@ -82,5 +115,24 @@ assert.deepEqual(result.generic_ability_names, []) assert.equal(result.adapter_ability_names.chat, "agents/chat") assert.equal(result.has_principal, false) assert.deepEqual(result.agents_api_input, { has_principal: true, source: "peer-agent", peer_agent_call: true, effective_agent_id: "agents-api-agent" }) +assert.deepEqual(result.materializer_input, { + operation: "apply", + source: { type: "artifact", artifact: { schema: "blocks-engine/php-transformer/site-artifact/v1", root: "website" } }, + slug: "canonical-site", + name: "Canonical Site", + site_title: "Canonical Site", + activate: true, + overwrite: true, + fail_on_quality: true, + source_metadata: { generator: "wp-build" }, + validation_artifacts: { screenshots: ["before.png", "after.png"] }, + validation_policy: { schema: "wp-build/visual-parity-validation-policy/v1", required: true }, +}) +assert.equal("artifact_bundle" in result.materializer_input, false) +assert.deepEqual(result.materializer_transport, { + task: "static-site-importer/import", + project_id: 2220, + validation_policy: { schema: "wp-build/visual-parity-validation-policy/v1", required: true }, +}) console.log("browser runtime generic invoker ok") diff --git a/tests/cloudflare-runtime.test.ts b/tests/cloudflare-runtime.test.ts index 8cbe81fd8..b60e9c3b0 100644 --- a/tests/cloudflare-runtime.test.ts +++ b/tests/cloudflare-runtime.test.ts @@ -83,6 +83,20 @@ test("Cloudflare static artifact imports require bounded content-addressed R2 in await assert.rejects(() => readStaticArtifactImport(new Request("https://worker.example/", { method: "POST", body: "x".repeat(16 * 1024 + 1) }), bucket as never), /request exceeds its byte budget/) }) +test("Cloudflare static artifact imports invoke SSI with the canonical apply input", async () => { + const worker = await readFile(new URL("../packages/runtime-cloudflare/src/worker.ts", import.meta.url), "utf8") + assert.doesNotMatch(worker, /static-site-importer\/import-website-artifact/) + assert.match(worker, /'operation' => 'apply'/) + assert.match(worker, /'source' => array\(\s*'type' => 'artifact',\s*'artifact' => \$artifact,/) + assert.match(worker, /'slug' => \$input\['slug'\]/) + assert.match(worker, /'name' => \$input\['name'\]/) + assert.match(worker, /'site_title' => \$input\['siteTitle'\]/) + assert.match(worker, /'activate' => true/) + assert.match(worker, /'overwrite' => true/) + assert.match(worker, /'fail_on_quality' => true/) + assert.match(worker, /'source_metadata' => array\('provider' => 'wp-codebox-cloudflare'/) +}) + test("Cloudflare upload manifests reject unbounded or non-canonical R2 files", () => { const sha256 = "a".repeat(64) const valid = [{ path: "2026/07/photo.png", size: 128, sha256, objectKey: `${R2_UPLOAD_OBJECT_PREFIX}/${sha256}` }] From 10f649a7c3b8d43660d0c6c135f5474ddd83b66d Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Wed, 5 Aug 2026 13:25:25 -0400 Subject: [PATCH 2/2] refactor: send SSI file sources [AI: OpenAI GPT-5.6 Sol via OpenCode] --- packages/runtime-cloudflare/README.md | 2 +- packages/runtime-cloudflare/src/worker.ts | 5 +++-- scripts/php-browser-contained-site-contract-smoke.php | 2 +- tests/browser-runtime-generic-invoker.test.ts | 7 ++++--- tests/cloudflare-runtime.test.ts | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/runtime-cloudflare/README.md b/packages/runtime-cloudflare/README.md index a10dd9bc5..837aa40c8 100644 --- a/packages/runtime-cloudflare/README.md +++ b/packages/runtime-cloudflare/README.md @@ -58,7 +58,7 @@ The D1 profile registers the configured site identity and creates or converges o Before canonical promotion, the operation checkpoints the exact prepared R2 pointer and expected coordinator version. Recovery skips SSI only when the coordinator's immutable commit receipt matches that complete pointer; a version match alone cannot claim another mutation's commit. The operation remains `publication-pending` after canonical commit until the corresponding immutable R2 publication receipt records promotion, supersession, or orphaning. Its terminal receipt identifies the artifact digest, SSI report, canonical pointer/version, publication identity, site URL, and canonical and terminal completion times. Profiles without a D1 operation repository retain the direct import transaction. -The import transaction boots a dedicated runtime with the pinned Static Site Importer v1.3.6 archive (`fb3679d679c03422fa77f5f33bc549fa869b0ce2bb16f7431705af4fc16b97db`) from R2 and invokes its public `static-site-importer/import` ability as the operator-authorized administrator. Its exact canonical input uses `operation: "apply"`, an artifact source envelope, deterministic slug/name/site title, activation, overwrite, quality failure, and Cloudflare artifact provenance. The transaction requires the canonical quality gate plus zero fallback, core HTML, freeform, and invalid blocks. SSI and its MU loader are runtime-owned and excluded from canonical mutable `wp-content`; generated themes, pages, options, and assets persist normally through MDI/R2. Failed or partial imports discard the PHP runtime without committing. Successful imports persist compact provenance, enqueue affected publication routes, and store at most 20 idempotency receipts in canonical options as a second mutation fence behind the D1 operation record. Exact replay converges without a new revision; reuse with different input returns a conflict. +The import transaction boots a dedicated runtime with the pinned Static Site Importer v1.3.6 archive (`fb3679d679c03422fa77f5f33bc549fa869b0ce2bb16f7431705af4fc16b97db`) from R2 and invokes its public `static-site-importer/import` ability as the operator-authorized administrator. Its exact canonical input uses `operation: "apply"`, a files source containing the artifact entrypoint and files, deterministic slug/name/site title, activation, overwrite, quality failure, and Cloudflare artifact provenance. The transaction requires the canonical quality gate plus zero fallback, core HTML, freeform, and invalid blocks. SSI and its MU loader are runtime-owned and excluded from canonical mutable `wp-content`; generated themes, pages, options, and assets persist normally through MDI/R2. Failed or partial imports discard the PHP runtime without committing. Successful imports persist compact provenance, enqueue affected publication routes, and store at most 20 idempotency receipts in canonical options as a second mutation fence behind the D1 operation record. Exact replay converges without a new revision; reuse with different input returns a conflict. SSI is extracted only for import requests, so normal browser, mutation, publication, and cron boots retain their existing memory and latency profile. The pinned normal plugin archive bundles Blocks Engine and supports website artifacts without the optional Figma zstd extension; compressed `.fig` import is outside this runtime contract. diff --git a/packages/runtime-cloudflare/src/worker.ts b/packages/runtime-cloudflare/src/worker.ts index ec5cd1430..110a92831 100644 --- a/packages/runtime-cloudflare/src/worker.ts +++ b/packages/runtime-cloudflare/src/worker.ts @@ -178,8 +178,9 @@ if (!$ability) { $ability_input = array( 'operation' => 'apply', 'source' => array( - 'type' => 'artifact', - 'artifact' => $artifact, + 'type' => 'files', + 'entrypoint' => (string) ($artifact['entrypoint'] ?? ''), + 'files' => isset($artifact['files']) && is_array($artifact['files']) ? $artifact['files'] : array(), ), 'slug' => $input['slug'], 'name' => $input['name'], diff --git a/scripts/php-browser-contained-site-contract-smoke.php b/scripts/php-browser-contained-site-contract-smoke.php index 8b9f0a219..78a182d6e 100644 --- a/scripts/php-browser-contained-site-contract-smoke.php +++ b/scripts/php-browser-contained-site-contract-smoke.php @@ -179,7 +179,7 @@ function expect( bool $condition, string $message ): void { 'name' => 'static-site-importer/import', 'input' => array( 'operation' => 'apply', - 'source' => array( 'type' => 'artifact', 'artifact' => array( 'schema' => 'blocks-engine/php-transformer/site-artifact/v1' ) ), + 'source' => array( 'type' => 'files', 'entrypoint' => 'website/index.html', 'files' => array() ), ), ), ), diff --git a/tests/browser-runtime-generic-invoker.test.ts b/tests/browser-runtime-generic-invoker.test.ts index 87c6a5765..ed45f214b 100644 --- a/tests/browser-runtime-generic-invoker.test.ts +++ b/tests/browser-runtime-generic-invoker.test.ts @@ -61,8 +61,9 @@ $agents_api_input = wp_codebox_browser_runtime_prepare_input( $agents_api_payloa $materializer_input = array( 'operation' => 'apply', 'source' => array( - 'type' => 'artifact', - 'artifact' => array( 'schema' => 'blocks-engine/php-transformer/site-artifact/v1', 'root' => 'website' ), + 'type' => 'files', + 'entrypoint' => 'website/index.html', + 'files' => array( array( 'path' => 'website/index.html', 'content' => '

Canonical

' ) ), ), 'slug' => 'canonical-site', 'name' => 'Canonical Site', @@ -117,7 +118,7 @@ assert.equal(result.has_principal, false) assert.deepEqual(result.agents_api_input, { has_principal: true, source: "peer-agent", peer_agent_call: true, effective_agent_id: "agents-api-agent" }) assert.deepEqual(result.materializer_input, { operation: "apply", - source: { type: "artifact", artifact: { schema: "blocks-engine/php-transformer/site-artifact/v1", root: "website" } }, + source: { type: "files", entrypoint: "website/index.html", files: [{ path: "website/index.html", content: "

Canonical

" }] }, slug: "canonical-site", name: "Canonical Site", site_title: "Canonical Site", diff --git a/tests/cloudflare-runtime.test.ts b/tests/cloudflare-runtime.test.ts index b60e9c3b0..add9e9503 100644 --- a/tests/cloudflare-runtime.test.ts +++ b/tests/cloudflare-runtime.test.ts @@ -87,7 +87,7 @@ test("Cloudflare static artifact imports invoke SSI with the canonical apply inp const worker = await readFile(new URL("../packages/runtime-cloudflare/src/worker.ts", import.meta.url), "utf8") assert.doesNotMatch(worker, /static-site-importer\/import-website-artifact/) assert.match(worker, /'operation' => 'apply'/) - assert.match(worker, /'source' => array\(\s*'type' => 'artifact',\s*'artifact' => \$artifact,/) + assert.match(worker, /'source' => array\(\s*'type' => 'files',\s*'entrypoint' => \(string\) \(\$artifact\['entrypoint'\] \?\? ''\),\s*'files' => isset\(\$artifact\['files'\]\)/) assert.match(worker, /'slug' => \$input\['slug'\]/) assert.match(worker, /'name' => \$input\['name'\]/) assert.match(worker, /'site_title' => \$input\['siteTitle'\]/)